【问题标题】:Hide or Remove vertical line in a specific point D3 chart隐藏或删除特定点 D3 图表中的垂直线
【发布时间】:2017-08-25 00:12:03
【问题描述】:

我使用 d3 绘制了一条多系列线,并在鼠标悬停在点上时添加了一条垂直线。我想隐藏没有数据的 2018 点中的垂直线和文本。我不知道如何在translate(415,0)的特定点选择线,所以我无法将样式更改为display:none

代码如下:

var data =[
{
    'timescale': '2015', 
    'Not': 31, 
    'Nearly': 59, 
    'Standard': 81,
    'Exceed':100
  },
  {
    'timescale': '2016', 
  'Not': 28, 
    'Nearly': 55, 
    'Standard': 78,
    'Exceed':100
  },
  {
    'timescale': '2017', 
  'Not': 25, 
    'Nearly': 51, 
    'Standard': 75,
    'Exceed':100
  },
  {
    'timescale': '2018', 
 'Not': "null", 
    'Nearly': "null", 
    'Standard': "null",
    'Exceed':"null"
  },
  {
    'timescale': '2019', 
 'Not': 41, 
    'Nearly': 67, 
    'Standard': 90,
    'Exceed':100
  },
  {
    'timescale': '2020', 
'Not': 36, 
    'Nearly': 61, 
    'Standard': 86,
    'Exceed':100
  },
  {
    'timescale': '2021', 
'Not': 31, 
    'Nearly': 55, 
    'Standard': 82,
    'Exceed':100
  }
];






//d3.csv("test.csv", function(error,data){
  console.log(data);
// set the dimensions and margins of the graph
var margin = { top: 20, right: 80, bottom: 30, left: 50 },  
    svg = d3.select('svg'),
    width = +svg.attr('width') - margin.left - margin.right,
    height = +svg.attr('height') - margin.top - margin.bottom;
var g = svg.append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// set the ranges
var x = d3.scaleBand().rangeRound([0, width]).padding(1),
    y = d3.scaleLinear().rangeRound([height, 0]),
    z = d3.scaleOrdinal(["#BBB84B","#789952","#50DB51","#2D602A"]);

// define the line
var line = d3.line()
.defined(function (d) { 
      return !isNaN(d.total); 
    })
  .x(function(d) { return x(d.timescale); })
  .y(function(d) { return y(d.total); });


// scale the range of the data
z.domain(d3.keys(data[0]).filter(function(key) {
  return key !== "timescale";
}));

var trends = z.domain().map(function(name) {
  return {
    name: name,
    values: data.map(function(d) {
      return {
        timescale: d.timescale,
        total: +d[name]
      };
    })
  };
});

x.domain(data.map(function(d) { return d.timescale; }));
y.domain([0, d3.max(trends, function(c) {
  return d3.max(c.values, function(v) {
    return v.total;
  });
})]);


// Draw the line
var trend = g.selectAll(".trend")
  .data(trends)
  .enter()
  .append("g")
  .attr("class", "trend");

trend.append("path")
  .attr("class", "line")
  .attr("d", function(d) { return line(d.values); })
  .style("stroke", function(d) { return z(d.name); });

// Draw the empty value for every point
var points = g.selectAll('.points')
  .data(trends)
  .enter()
  .append('g')
  .attr('class', 'points')
  .append('text');

// Draw the circle
trend
  .style("fill", "#FFF")
  .style("stroke", function(d) { return z(d.name); })
  .selectAll("circle.line")
  .data(function(d){return d.values} )
  .enter()
  .append("circle")
  .filter(function(d) { return d.timescale !== "2018" })
  .attr("r", 5)
  .style("stroke-width", 3)
  .attr("cx", function(d) { return x(d.timescale); })
  .attr("cy", function(d) { return y(d.total); });
  

// Draw the axis
g.append("g")
  .attr("class", "axis axis-x")
  .attr("transform", "translate(0, " + height + ")")
  .call(d3.axisBottom(x));

g.append("g")
  .attr("class", "axis axis-y")
  .call(d3.axisLeft(y).ticks(6));

var focus = g.append('g')
  .attr('class','focus')
  .style('display', 'none');

focus.append('line')
  .attr('class', 'x-hover-line hover-line')
  .attr('y1' , 0)
  .attr('y2', height)
  .style('stroke',"black");

svg.append('rect')
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  .attr("class", "overlay")
  .attr("width", width)
  .attr("height", height)
  .on("mouseover", mouseover)
  .on("mouseout", mouseout)
  .on("mousemove", mousemove);

// var timeScales = data.map(function(name) { return x(name.timescale); });
// console.log(timeScales);

var timeScales = [106,209,312,415,518,621,724];
// d3.select('.focus')
//       .attr("x1",415)
//       .attr("y1",0)
//       .attr("x2",415)
//       .attr("y2",height)
//       .style("display","none");

function mouseover() {
  
  focus.style("display", null);
  d3.selectAll('.points text').style("display", null);
}
function mouseout() {
  focus.style("display", "none");
  d3.selectAll('.points text').style("display", "none");
}
function mousemove() {
  var i = d3.bisect(timeScales, d3.mouse(this)[0], 1);
  var di = data[i-1];
  focus.attr("transform", "translate(" + x(di.timescale) + ",0)");

  d3.selectAll('.points text')
    .attr('x', function(d) { return x(di.timescale) + 5; })
    .attr('y', function(d) { return y(d.values[i-1].total)-5; })
    .text(function(d) { return d.values[i-1].total; })
    .style('fill', function(d) { return z(d.name); });
}
body {
    font-family: 'Proxima Nova', Georgia, sans-serif;
}

.line {
  fill: none;
  stroke-width: 3px;
}

.overlay {
  fill: none;
  pointer-events: all;
}

.hover-line {

  stroke-width: 2px;
  stroke-dasharray: 3,3;
}
<svg width="960" height="500"></svg>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js'></script>

【问题讨论】:

    标签: javascript css d3.js


    【解决方案1】:

    在 mousemove 函数中,仅当 timescale 不是 2018 时才执行转换:

    function mousemove() {
      var i = d3.bisect(timeScales, d3.mouse(this)[0], 1);
      var di = data[i-1];
    
      if (di.timescale !== '2018') {
        focus.attr("transform", "translate(" + x(di.timescale) + ",0)");
    
        d3.selectAll('.points text')
          .attr('x', function(d) { return x(di.timescale) + 5; })
          .attr('y', function(d) { return y(d.values[i-1].total)-5; })
          .text(function(d) { return d.values[i-1].total; })
          .style('fill', function(d) { return z(d.name); });
        }
    }
    

    【讨论】:

    • 酷。谢谢你。我今天也修好了。我没有使用 di.timescale,而是使用了 i !==4。在您的代码中,当您将鼠标悬停在 2018 年时,2017 年的点文本并没有消失,所以我认为最好做一个 if else 语句。这是我的代码:
    • ' if(i !== 4){ focus.attr("transform", "translate(" + x(di.timescale) + ",0)"); focus.style("display",null); d3.selectAll('.points text') .style("display",null); d3.selectAll('.points text') .attr('x', function(d) { return x(di.timescale) + 5; }) .attr('y', function(d) { return y(d .values[i-1].total)-5; }) .text(function(d) { return d.values[i-1].total; }) .style('fill', function(d) { return z(d.name); }); }else{ focus.style("display","none"); d3.selectAll('.points text') .style("display","none");'
    • 我明白了,只有2018点的文字消失了。正如您所指出的, if else 在这种情况下效果更好。如果您认为有帮助,请不要忘记为答案投票。
    【解决方案2】:

    你有使用二等分作为提示

    所以它只会在它被选中时绘制,让我们改变它,这样它就不会在鼠标悬停时绘制 2018

    var data =[
    {
        'timescale': '2015', 
        'Not': 31, 
        'Nearly': 59, 
        'Standard': 81,
        'Exceed':100
      },
      {
        'timescale': '2016', 
      'Not': 28, 
        'Nearly': 55, 
        'Standard': 78,
        'Exceed':100
      },
      {
        'timescale': '2017', 
      'Not': 25, 
        'Nearly': 51, 
        'Standard': 75,
        'Exceed':100
      },
      {
        'timescale': '2018', 
     'Not': "null", 
        'Nearly': "null", 
        'Standard': "null",
        'Exceed':"null"
      },
      {
        'timescale': '2019', 
     'Not': 41, 
        'Nearly': 67, 
        'Standard': 90,
        'Exceed':100
      },
      {
        'timescale': '2020', 
    'Not': 36, 
        'Nearly': 61, 
        'Standard': 86,
        'Exceed':100
      },
      {
        'timescale': '2021', 
    'Not': 31, 
        'Nearly': 55, 
        'Standard': 82,
        'Exceed':100
      }
    ];
    
    
    
    
    
    
    //d3.csv("test.csv", function(error,data){
     // console.log(data);
    // set the dimensions and margins of the graph
    var margin = { top: 20, right: 80, bottom: 30, left: 50 },  
        svg = d3.select('svg'),
        width = +svg.attr('width') - margin.left - margin.right,
        height = +svg.attr('height') - margin.top - margin.bottom;
    var g = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    // set the ranges
    var x = d3.scaleBand().rangeRound([0, width]).padding(1),
        y = d3.scaleLinear().rangeRound([height, 0]),
        z = d3.scaleOrdinal(["#BBB84B","#789952","#50DB51","#2D602A"]);
    
    // define the line
    var line = d3.line()
    .defined(function (d) { 
          return !isNaN(d.total); 
        })
      .x(function(d) { return x(d.timescale); })
      .y(function(d) { return y(d.total); });
    
    
    // scale the range of the data
    z.domain(d3.keys(data[0]).filter(function(key) {
      return key !== "timescale";
    }));
    
    var trends = z.domain().map(function(name) {
      return {
        name: name,
        values: data.map(function(d) {
          return {
            timescale: d.timescale,
            total: +d[name]
          };
        })
      };
    });
    
    x.domain(data.map(function(d) { return d.timescale; }));
    y.domain([0, d3.max(trends, function(c) {
      return d3.max(c.values, function(v) {
        return v.total;
      });
    })]);
    
    
    // Draw the line
    var trend = g.selectAll(".trend")
      .data(trends)
      .enter()
      .append("g")
      .attr("class", "trend");
    
    trend.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return z(d.name); });
    
    // Draw the empty value for every point
    var points = g.selectAll('.points')
      .data(trends)
      .enter()
      .append('g')
      .attr('class', 'points')
      .append('text');
    
    // Draw the circle
    trend
      .style("fill", "#FFF")
      .style("stroke", function(d) { return z(d.name); })
      .selectAll("circle.line")
      .data(function(d){return d.values} )
      .enter()
      .append("circle")
      .filter(function(d) { return d.timescale !== "2018" })
      .attr("r", 5)
      .style("stroke-width", 3)
      .attr("cx", function(d) { return x(d.timescale); })
      .attr("cy", function(d) { return y(d.total); });
      
    
    // Draw the axis
    g.append("g")
      .attr("class", "axis axis-x")
      .attr("transform", "translate(0, " + height + ")")
      .call(d3.axisBottom(x));
    
    g.append("g")
      .attr("class", "axis axis-y")
      .call(d3.axisLeft(y).ticks(6));
    
    var focus = g.append('g')
      .attr('class','focus')
      .style('display', 'none');
    
    focus.append('line')
      .attr('class', 'x-hover-line hover-line')
      .attr('y1' , 0)
      .attr('y2', height)
      .style('stroke',"black");
    
    svg.append('rect')
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", mouseover)
      .on("mouseout", mouseout)
      .on("mousemove", mousemove);
    
    // var timeScales = data.map(function(name) { return x(name.timescale); });
    // console.log(timeScales);
    
    var timeScales = [106,209,312,415,518,621,724];
    // d3.select('.focus')
    //       .attr("x1",415)
    //       .attr("y1",0)
    //       .attr("x2",415)
    //       .attr("y2",height)
    //       .style("display","none");
    
    function mouseover() {
    
      focus.style("display", null);
      d3.selectAll('.points text').style("display", null);
    }
    function mouseout() {
      focus.style("display", "none");
      d3.selectAll('.points text').style("display", "none");
    }
    function mousemove() {
      var i = d3.bisect(timeScales, d3.mouse(this)[0], 1);
      var di = data[i-1];
      console.log(di)
      if (di.timescale =="2018"){
      focus.style('display','none')
        d3.selectAll('.points text').style("display", "none");
      }else{
      focus.style('display','block')
      d3.selectAll('.points text').style("display", "block");
      focus.attr("transform", "translate(" + x(di.timescale) + ",0)");}
    
      d3.selectAll('.points text')
        .attr('x', function(d) { return x(di.timescale) + 5; })
        .attr('y', function(d) { return y(d.values[i-1].total)-5; })
        .text(function(d) { return d.values[i-1].total; })
        .style('fill', function(d) { return z(d.name); });
    }
    body {
        font-family: 'Proxima Nova', Georgia, sans-serif;
    }
    
    .line {
      fill: none;
      stroke-width: 3px;
    }
    
    .overlay {
      fill: none;
      pointer-events: all;
    }
    
    .hover-line {
    
      stroke-width: 2px;
      stroke-dasharray: 3,3;
    }
    <svg width="960" height="500"></svg>
      <script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js'></script>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-27
      • 2014-04-29
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多