d3悬停文本到剪切路径

时间:2020-11-07 19:40:58

标签: d3.js hover tooltip clip-path

我正在尝试将悬停工具提示添加到剪切路径[这是我第一次使用clippath ...甚至是正确的单词吗?] ...我想我真的很接近[圆圈该行应该现在显示在(0.0)处],但我似乎缺少了一些内容。我想知道是否有人有时间看看?我正在尝试改编https://blockbuilder.org/bendoesdata/2c8b315d103bbaf98264efda92d313ab

中的代码

.tooltip {
    position: absolute;
    text-align: left;
    font-family: "Open Sans Condensed";
    font-size: 12px;
    width: 80px;
    height: 52px;
    padding: 8px;
    background: white;
    pointer-events: none;
    background-color: white;
    line-height: 0.05em;
    padding: 20px;
    /* border: solid;
        border-width: 1px; */
  }

  #my_dataviz {
    padding: 20px;
  }
<script src="https://d3js.org/d3.v5.js"></script>
<div id="my_dataviz"></div>
        
        headers = randint(0, 1)
        with open('headers.csv', 'r') as fd:
            reader = csv.reader(fd)
            reader = list(reader)
            driver.execute_cdp_cmd('Network.setUserAgentOverride', {
                                    "userAgent": str(reader[headers])})    
        
       

1 个答案:

答案 0 :(得分:1)

  1. 您混淆了命名。 ser1您多次致电str1。这清楚地表明您的原始命名ser1ser2不够逻辑!如果您现在不能遵循它,那么一年后重新访问代码又如何呢?

  2. 在使用数据之前先解析数据,而不是在使用时解析。如果您将日期作为字符串存储在原始对象中,请在对其进行处理之前 对其进行解析。否则,当您想比较,绘制,格式化或使用它时,就会遇到问题。

就是这样,我所做的大部分更改只是在需要时将formatDate替换为parseDate(这些是不同的东西),然后将str1/2替换为ser1/2在任何需要的地方。

var data3 = [
  { group: 1, ser1: "2020-01-01", ser2: 3 },
  { group: 1, ser1: "2020-01-02", ser2: 5 },
  { group: 1, ser1: "2020-01-03", ser2: 9 },
  { group: 1, ser1: "2020-01-04", ser2: 3 },
  { group: 1, ser1: "2020-01-05", ser2: 5 },
  { group: 1, ser1: "2020-01-06", ser2: 9 },
  { group: 2, ser1: "2020-01-07", ser2: 10 },
  { group: 2, ser1: "2020-01-08", ser2: 9 },
  { group: 2, ser1: "2020-01-09", ser2: 10 },
  { group: 2, ser1: "2020-01-10", ser2: 20 },
  { group: 2, ser1: "2020-01-11", ser2: 10 },
  { group: 2, ser1: "2020-01-12", ser2: 12 },
  { group: 3, ser1: "2020-01-13", ser2: 20 },
  { group: 3, ser1: "2020-01-14", ser2: 12 },
  { group: 3, ser1: "2020-01-15", ser2: 4 },
  { group: 3, ser1: "2020-01-16", ser2: 22 },
  { group: 3, ser1: "2020-01-17", ser2: 2 },
  { group: 3, ser1: "2020-01-18", ser2: 4 },
];

var parseDate = d3.timeParse("%Y-%m-%d");
// Parse the date ASAP
data3 = data3.map(function(d) {
  return {
    group: d.group,
    ser1: parseDate(d.ser1),
    ser2: d.ser2
  };
});

var line = d3.line()
  .x(function (d) { return x(d.ser1); })
  .y(function (d) { return y(d.ser2); })

// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 30, left: 50 },
  width = 1000 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("viewBox", `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

svg.append("defs")
  .append("clipPath")
  .attr("id", "chart-path")
  .append("rect")
  .attr("width", width - 100)
  .attr("height", height)

var formatDate = d3.timeParse("%Y-%m-%d");

var bisectDate = d3.bisector(function (d) {
  return d.ser1;
}).left;

// Initialize a X axis:
var x = d3.scaleTime()
  .range([0, width - 100])
  .domain(d3.extent(data3, function (d) { return d.ser1; }));
var xNum = d3.scaleLinear().range([0, width - 100])
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .attr("class", "myXaxis")

// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
  .attr("class", "myYaxis")

// create the Y axis
y.domain([0, d3.max(data3, function (d) { return d.ser2 })]);
svg.selectAll(".myYaxis")
  .transition()
  .duration(1000)
  .call(yAxis);

// Create a update selection: bind to the new data
var u = svg.selectAll(".lineTest")
  .data([data3])
  .enter()
  .append("path")
  .attr("class", "lineTest")
  .attr("fill", "none")
  .attr("stroke", "#0b6dbd")
  .attr("stroke-width", 2.5)
  .attr("clip-path", "url(#chart-path)")

svg.selectAll(".myXaxis")
  .call(xAxis);
u.attr("d", line);

// this is where I try to implement a tooltip based on
// https://blockbuilder.org/bendoesdata/2c8b315d103bbaf98264efda92d313ab
function drawFocus() {
  // Create focus object
  let focus = svg.append('g')
    .attr('class', 'focus')

  // append circle on the line path
  focus.append('circle')
    .attr('r', 7.5)

  // add background rectangle behind the text tooltip
  focus.append('rect')
    .attr('x', -30)
    .attr('y', '-2em')
    .attr('width', 70)
    .attr('height', 20)
    .style("fill", "white");

  // add text annotation for tooltip
  focus.append('text')
    .attr('x', -30)
    .attr('dy', '-1em')
    .style("fill", "black")
    .style("font-family", "SuisseIntl");

  focus.append('div')
    .attr('x', 10)
    .attr('dy', '.35em')
    .attr("class", "tooltip")
    .style("opacity", 1)

  // create an overlay rectangle to draw the above objects on top of
  svg.append('rect')
    .attr('class', 'overlay')
    .attr('width', width - 100)
    .attr('height', height)
    .on('mouseover', () => focus.style('display', null))
    .on('mouseout', () => focus.style('display', 'none'))
    .on('mousemove', tipMove);

  // make the overlay rectangle transparent,
  // so it only serves the purpose of detecting mouse events
  d3.select('.overlay')
    .style('fill', 'none')
    .style('pointer-events', 'all');

  // select focus objects and set opacity
  d3.selectAll('.focus')
    .style('opacity', 0.9);

  // select the circle and style it
  d3.selectAll('.focus circle')
    .style("fill", '#FDD511')
    .style("opacity", 0)


  // function that adds tooltip on hover
  function tipMove() {
    // below code finds the date by bisecting and
    // stores the x and y coordinate as variables
    let x0 = x.invert(d3.mouse(this)[0]);
    let i = bisectDate(data3, x0, 1);
    let d0 = data3[i - 1];
    let d1 = data3[i];
    let d = x0 - d0.ser1 > d1.ser1 - x0 ? d1 : d0;

    // place the focus objects on the same path as the line
    focus.attr('transform', `translate(${x(d.ser1)}, ${y(d.ser2)})`);

    // position the x line
    focus.select('line.x')
      .attr('x1', 0)
      .attr('x2', x(d.ser1))
      .attr('y1', 0)
      .attr('y2', 0);

    // position the y line
    focus.select('line.y')
      .attr('x1', 0)
      .attr('x2', 0)
      .attr('y1', 0)
      .attr('y2', height - y(d.ser2));

    // position the text
    focus.select('text').text(d.ser2)
      .transition() // slowly fade in the tooltip
      .duration(100)
      .style("opacity", 1);

    // show the circle on the path
    focus.selectAll('.focus circle')
      .style("opacity", 1)

  };
}

drawFocus();
.tooltip {
    position: absolute;
    text-align: left;
    font-family: "Open Sans Condensed";
    font-size: 12px;
    width: 80px;
    height: 52px;
    padding: 8px;
    background: white;
    pointer-events: none;
    background-color: white;
    line-height: 0.05em;
    padding: 20px;
    /* border: solid;
        border-width: 1px; */
  }

  #my_dataviz {
    padding: 20px;
  }
<script src="https://d3js.org/d3.v5.js"></script>
<div id="my_dataviz"></div>

相关问题