边框为d3堆栈条形图选择 [英] border for d3 stack bar chart on selection

查看:62
本文介绍了边框为d3堆栈条形图选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试在d3堆栈条形图中为选定条实现边框。这里第一个酒吧的顶部边框略微落后于第二个酒吧。如何避免这种情况?

Trying to implement border for selected bar in d3 stack bar chart. Here the first bar's top border goes behind second bar a little bit. How to avoid this?

var svg, height, width, margin, parentWidth, parentHeight;

// container size
parentWidth = 700;
parentHeight = 500;
margin = {top: 50, right: 20, bottom: 35, left: 30};
width = parentWidth - margin.left - margin.right;
height = parentHeight - margin.top - margin.bottom;

var selectedSection = window.sessionStorage.getItem('selectedSection');

// data
var dataset = [{"label":"DEC","Set Up":{"count":12,"id":1,"label":"Set Up","year":"2016","graphType":"setup"},"Not Set Up":{"count":12,"id":0,"label":"Not Set Up","year":"2016","graphType":"setup"}},{"label":"JAN","Set Up":{"count":6,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":21,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"FEB","Set Up":{"count":1,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":2,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"MAR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}},{"label":"APR","Set Up":{"count":0,"id":1,"label":"Set Up","year":"2017","graphType":"setup"},"Not Set Up":{"count":0,"id":0,"label":"Not Set Up","year":"2017","graphType":"setup"}}];

// x cord
var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], 0.2);

// color helper
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
    .range(colorRange.range());

// x axis
var xAxis = d3.svg.axis()
    .scale(x)
    .orient('bottom');

var colors = ['#50BEE9', '#30738C'];

// Set SVG
svg = d3.select('#chart')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom )
  .attr('class', 'setup')
  .append('g')
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== 'label'; }));

dataset.forEach(function(d) {
  var y0 = 0;
  d.values = color.domain().map(function(name) { 
    return {
      name: name, 
      y0: y0, 
      y1: y0 += +d[name].count, 
      patientStatus:d[name].id,
      graphType:d[name].graphType,  
      fromDate:{
        month:d.label,
        year:d[name].year
      },
      toDate:{
        month:d.label,
        year:d[name].year
      }  
    }; 
  });
  d.total = d.values[d.values.length - 1].y1;
});

var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) {  
    return d.total;
  })])
    .range([height, 0]);

var ticks = y.ticks(),
    lastTick = ticks[ticks.length-1];    
var newLastTick = lastTick + (ticks[1] - ticks[0]);  
if (lastTick<y.domain()[1]){
  ticks.push(lastTick + (ticks[1] - ticks[0]));
}

// adjust domain for further value
y.domain([y.domain()[0], newLastTick]);

// y axis
var yAxis = d3.svg.axis()
    .scale(y)
    .orient('left')
    .tickSize(-width, 0, 0) 
    .tickFormat(d3.format('d'))
    .tickValues(ticks);

x.domain(dataset.map(function(d) { return d.label; }));
y.domain([0, d3.max(dataset, function(d) { return d.total; })]);

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

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

var bar = svg.selectAll('.label')
    .data(dataset)
    .enter().append('g')
    .attr('class', 'g')
    .attr('id', function(d, i) {
    return i;
  })
    .attr('transform', function(d) { return 'translate(' + x(d.label) + ',0)'; });

var barEnter = bar.selectAll('rect')
    .data(function(d) { return d.values; })
    .enter();

barEnter.append('rect')
  .attr('width', x.rangeBand())
  .attr('y', function(d) { 
    return y(d.y1); 
    })
  .attr('class', function(d, i){
    return 'bar';
    })
  .attr('height', function(d) { return y(d.y0) - y(d.y1); })
  .style('fill', function(d,i) { return colors[i]; })
  .on('click', function(d, i) {
    d3.selectAll('.bar').classed('selected', false);
    d3.select(this)
      .classed('bar selected', true);  
    });

barEnter.append('text')
  .text(function(d) { 
    var calcH = y(d.y0) - y(d.y1);
    var inText = (d.y1-d.y0);
    if(calcH >= 20) {
      return inText;
    } else {
      return '';
    }
})
.attr('class','inner-text')
.attr('y', function(d) { return y(d.y1)+(y(d.y0) - y(d.y1))/2 + 5; })
.attr('x', function(){
  return (x.rangeBand()/2) - 10;
}); 

svg
  .select('.y')
  .selectAll('.tick')
  .filter(function (d) { 
    return d % 1 !== 0;    
    })
  .style('display','none');

svg
  .select('.y')
  .selectAll('.tick')
  .filter(function (d) { 
    return d === 0;    
    })
  .select('text')
  .style('display','none');

JSFiddle

JSFiddle

JSFiddle with d3 v4

推荐答案

在SVG中,就像真正的画家将墨水放到白色画布上一样,最后绘制的元素保持在最顶层。

In a SVG, just like a real painter putting ink to a white canvas, the element that is painted last stays on top.

现在,你看到的行为是预期的一个,因为每个堆叠的条形(矩形)在不同的< g> 元素中,当然,这些组在SVG结构中具有给定的顺序。

Right now, the behaviour you're seeing is the expected one, because each stacked bar (rectangle) is in a different <g> element, and the groups, of course, have a given order in the SVG structure.

解决方案只涉及一行:

d3.select(this.parentNode).raise();

这一行的作用是选择点击的矩形组并将其抬起(即移动它在DOM树中向下),以便该组将位于所有其他组之上。根据API, raise()

What this line does is selecting the group of the clicked rectangle and raising it (that is, moving it down in the DOM tree), so that group will be on top of all others. According to the API, raise():


按顺序重新插入每个选定元素作为其父级的最后子元素。 (强调我的)

Re-inserts each selected element, in order, as the last child of its parent. (emphasis mine)

向下移动在顶部成为最后一个孩子可能有点令人困惑,看起来很矛盾,但这里有解释。鉴于此SVG结构:

"Moving down", "be on top" and "be the last child" may be a bit confusing and seem contradictory, but here is the explanation. Given this SVG structure:

<svg>
    <foo></foo>
    <bar></bar>
    <baz></baz>
</svg>

< baz> ,是最后一个元素,是绘制最后的元素,它是SVG顶部的视觉元素。因此,提升元素意味着在SVG树结构中将其向下移动,但在视觉上将其移动向上

<baz>, being the last element, is the one painted last, and it is the element visually on the top in the SVG. So, raising an element means moving it down in the SVG tree structure, but moving it up visually speaking.

以下是您更新的小提琴: https://jsfiddle.net/86Lgaupt/

Here is your updated fiddle: https://jsfiddle.net/86Lgaupt/

PS:我增加了笔画宽度,只是为了明确点击的矩形现在位于顶部。

PS: I increased the stroke-width just to make visibly clear that the clicked rectangle is now on top.

这篇关于边框为d3堆栈条形图选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆