如何在D3中折线图的末尾添加工具提示

时间:2019-06-25 21:42:58

标签: javascript d3.js

我有一条LOESS线,我想添加一个工具提示来标记它。

我试图获取直线的最后一点的坐标,但是我得到了一个字符串并且无法获取最后一点

loessRegression_e = d3.regressionLoess()
   .x(d => d.fecha_de_libertad)
   .y(d => d.EXTERNADO)
   .bandwidth(0.20);

var valueline = d3.line()
    .x(function(d) { return x(d[0]); })
    .y(function(d) { return y(d[1]); })
    .curve(d3.curveCatmullRom);

console.log(valueline(loessRegression_e(data))) // Here is where I tried to get the coordinates of the line, but it is a string, and a pain to slice it

var div = d3.select("body").append("div")
    .attr("class", "tooltip")
    .style("display", "none");

div
   .text(d3.event.pageX + ", " + d3.event.pageY)
   .style("left", (d3.event.pageX - 34) + "px")
   .style("top", (d3.event.pageY - 12) + "px");

svg.append("path")
   .data([loessRegression_e(data)])
   .attr("class", "line_e")
   .attr("d", valueline);

// Add the x-axis.
svg.append("g")
   .attr("class", "x axis")
   .attr("transform", "translate(0," + height + ")")
   .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%Y-%m-%d")));

    // Add the y-axis.
svg.append("g")
   .attr("class", "y axis")
   .call(d3.axisLeft(y));

// Add the points!
svg.selectAll(".point")
    .data(data)
    .enter().append("path")
    .attr("class", "point")
    .attr("d", d3.symbol().type(d3.symbolSquare))
    .attr("transform", function(d) { return "translate(" + x(d.fecha_de_libertad) + "," + y(d.COMPURGADO) + ")"; });

1 个答案:

答案 0 :(得分:0)

您可以绑定添加鼠标悬停事件以显示您悬停的数据点。例如:

svg.append("path")
   .data([loessRegression_e(data)])
   .attr("class", "line_e")
   .attr("d", valueline)
   .on( 'mouseover', function( d ) {
       $( '.tooltip' ).text( "(" + d.x + "," + d.y ")" );
       $( '.tooltip' ).show();
     })
    .on( 'mouseout', function( d ) {
        $('.tooltip').hide(); 
     });

这假定您正在使用jquery,但如果没有,则可以轻松进行修改。

编辑:对不起,我忽略了一些事情。您不能在不使用异物的情况下将div直接添加到svg中,也不能将文本追加到圆上。因此,您可以将div添加到html中,并使用d3将div与绑定的数据一起放置。我已经附加了一个(草率的)最小工作示例,您可以在绘制线并根据最后一个元素显示标签时作为参考。免责声明:我敢肯定有一个更优雅的解决方案。

<!DOCTYPE html>
<html>
  <head>
    <style>
      .tool-tip {
        background-color: blue;
        height: 50px;
        width: 50px;
        z-index: 10;
        position: absolute;
        visibility: hidden;
      }
      .line {
        fill: none;
        stroke: steelblue;
        stroke-width: 2px;
      }
      #svg-container {
        position: relative;
      }

    </style>
  </head>

  <body>
    <div id="svg-container" >
      <div class='tool-tip'>WTF</div>
    </div>

  <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.1/d3.js"></script>

  </body>
  <script>
  let data = [{'x': 0, 'y': 0}, {'x':1, 'y': 1}, {'x': 2, 'y': 2}, {'x': 3, 'y': 3}]; //made up data
  let width = 500;
  let height = 500;
  let svg = d3.select( "#svg-container" ).append( "svg" ).attr( 'height', height ).attr( 'width', width ).attr( 'id', 'my-svg' )
  let xscale = d3.scaleLinear()
                  .domain( [0, 4])
                  .range( [ 0, width] )
  let yscale = d3.scaleLinear()
                  .domain( [0, 4] )
                  .range( [ height, 0] )

  let myline = d3.line()
     .x(d => xscale(d.x))
     .y(d => yscale(d.y))
   svg.append("path")
    .data( [data] )
    .attr("class", "line")
    .attr("d", myline);
  let point = svg.selectAll( 'circle' )
    .data( data )
    .enter()
    .append( 'circle' )
      .attr( 'r', 5 )
      .attr( 'cx', function(d) { return xscale( d.x ); })
      .attr( 'cy', function(d) { return yscale( d.y ); })
      .attr( 'fill', 'red' )
      .attr( 'class', 'my-circle' )

  //You start here
  //grab the last data point that you want to add a label to
  let label = svg.select( '.my-circle:last-of-type')

              //use fill method as a hook to bind the data to the label
              .attr( 'fill', function( d ) {

               //get the position to place the label from your data point
                let x = parseFloat($( this ).attr( 'cx' ));
                let y = parseFloat($( this ).attr( 'cy' ));

                //get the raw data point to display
                let x_invert = xscale.invert( x );
                let y_invert = yscale.invert( y );

                //use jquery to set the x and position using offset of 15 - may need to add your
                // svg x and y starting points if somewhere offset from the page
                $( '.tool-tip' ).text( "(" + d.x + "," + d.y + ")");
                $( '.tool-tip' ).css( 'left', (x + 15)  + 'px' );
                $( '.tool-tip' ).css( 'top', (y + 15)  + 'px');
                $( '.tool-tip' ).css( 'visibility', 'visible');

                //return the fill as we only called this to display the label.
                return $( this ).attr( 'fill' );

              })

  </script>
</html>