Javascript 选择时d3堆栈条形图的边框

Javascript 选择时d3堆栈条形图的边框,javascript,html,css,d3.js,svg,Javascript,Html,Css,D3.js,Svg,正在尝试为d3堆栈条形图中的选定条形图实现边框。在这里,第一个酒吧的上边框在第二个酒吧后面一点。如何避免这种情况 var svg, height, width, margin, parentWidth, parentHeight; // container size parentWidth = 700; parentHeight = 500; margin = {top: 50, right: 20, bottom: 35, left: 30}; width = parentWidth - m

正在尝试为d3堆栈条形图中的选定条形图实现边框。在这里,第一个酒吧的上边框在第二个酒吧后面一点。如何避免这种情况

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');
var svg、高度、宽度、边距、parentWidth、parentHeight;
//容器大小
parentWidth=700;
父母身高=500;
边距={顶部:50,右侧:20,底部:35,左侧:30};
宽度=parentWidth-margin.left-margin.right;
高度=父高度-margin.top-margin.bottom;
var selectedSection=window.sessionStorage.getItem('selectedSection');
//资料
var数据集=[{“标签”:“DEC”,“设置”:“计数”:12,“id”:1,“标签”:“设置”,“年份”:“2016”,“图形类型”:“设置”},“未设置”:“计数”:12,“id”:0,“标签”:“未设置”,“年份”:“2016”,“图形类型”:“设置”},{“标签”:“一月”,“设置”:“计数”:6,“id”:1,“标签”:“设置”,“年份”:“2017”,“图形类型”:“设置”},“未设置”:“计数”:21,“id”:0,“标签”:“未设置”,“年份”:“2017年”,“图形类型”:“设置”},{“标签”:“2月”,“设置”:{“计数”:1,“id”:1,“标签”:“设置”,“年份”:“2017年”,“图形类型”:“设置”},“未设置”:{“计数”:2,“id”:0,“标签”:“未设置”,“年份”:“2017年”,“图形类型”:“设置”},{“标签”:“MAR“:”未设置“,”年份“:”2017“,”图形类型“:”设置“},{”标签“:”APR“,”设置“,”标签“:”设置“,”年份“:”2017“,”图形类型“:”设置“}”,未设置“{”计数“:”0,“id“:”标签“:”未设置“,”年份“:”2017“,”图形类型“:”设置“}”;
//x线
var x=d3.scale.ordinal()
.rangeRoundBands([0,宽度],0.2);
//颜色助手
var colorRange=d3.scale.category20();
var color=d3.scale.ordinal()
.range(colorRange.range());
//x轴
var xAxis=d3.svg.axis()
.比例(x)
.orient(“底部”);
变量颜色=['#50BEE9','#30738C'];
//设置SVG
svg=d3。选择(“#图表”)
.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(数据集[0]).filter(函数(键){return key!=='label';}));
dataset.forEach(函数(d){
var y0=0;
d、 values=color.domain().map(函数(名称){
返回{
姓名:姓名,,
y0:y0,
y1:y0+=+d[名称]。计数,
patientStatus:d[name].id,
graphType:d[名称]。graphType,
起始日期:{
月份:d.label,
年份:d[姓名]。年份
},
今天:{
月份:d.label,
年份:d[姓名]。年份
}  
}; 
});
d、 总计=d.values[d.values.length-1].y1;
});
变量y=d3.scale.linear()
.domain([0,d3.max(数据集,函数(d){
返回d.total;
})])
.范围([高度,0]);
var ticks=y.ticks(),
lastTick=ticks[ticks.length-1];
var newLastTick=lastTick+(ticks[1]-ticks[0]);
如果(lastTick=20){
返回inText;
}否则{
返回“”;
}
})
.attr('class','internal-text')
.attr('y',函数(d){返回y(d.y1)+(y(d.y0)-y(d.y1))/2+5;})
.attr('x',function(){
返回(x.rangeBand()/2)-10;
}); 
svg
.select(“.y”)
.selectAll(“.tick”)
.filter(函数(d){
返回d%1!==0;
})
.style('display','none');
svg
.select(“.y”)
.selectAll(“.tick”)
.filter(函数(d){
返回d==0;
})
.选择('文本')
.style('display','none');


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

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

解决方案只涉及一行:

d3.select(this.parentNode).raise();
这一行所做的是选择单击矩形的组并将其升高(即,在DOM树中将其向下移动),以便该组位于所有其他组的顶部。根据API:

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

“向下移动”、“站在顶端”和“成为最后一个孩子”可能有点混乱,似乎相互矛盾,但下面是解释。鉴于此SVG结构:

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

,作为最后一个元素,是绘制在SVG顶部的元素。因此,提升一个元素意味着在SVG树结构中向下移动它,但从视觉上来说,向上移动它

这是你最新的小提琴:

PS:我增加了笔划宽度,只是为了清楚地表明单击的矩形现在位于顶部。

标记:

  <div id='stacked-bar'></div>
Css:


这是正常的行为,因为在SVG中,最后一个绘制的人保持在顶部。如果您使用的是D3 v4.x,这一问题只需一行就可以解决…@GerardoFurtado您能为D3 v4中的修复提供一个提琴吗?不,这是一个很大的工作。既然您有兴趣解决这个问题,您应该使用v4创建小提琴。之后,我向您展示了解决方案。我用D3V4创建了一个小提琴。请帮我解决问题,还有邦蒂。
    var initStackedBarChart = {
    draw: function(config) {
        me = this,
        domEle = config.element,
        stackKey = config.key,
        data = config.data,
        margin = {top: 20, right: 20, bottom: 30, left: 50},
        parseDate = d3.timeParse("%m/%Y"),
        width = 550 - margin.left - margin.right,
        height = 400 - margin.top - margin.bottom,
        xScale = d3.scaleBand().range([0, width]).padding(0.1),
        yScale = d3.scaleLinear().range([height, 0]),
        color = d3.scaleOrdinal(d3.schemeCategory20),
        xAxis = d3.axisBottom(xScale).tickFormat(d3.timeFormat("%b")),
        yAxis =  d3.axisLeft(yScale),
        svg = d3.select("#"+domEle).append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top+10 + margin.bottom+10)
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var stack = d3.stack()
            .keys(stackKey)
            .order(d3.stackOrderNone)
            .offset(d3.stackOffsetNone);

        var layers= stack(data);
            data.sort(function(a, b) { return b.total - a.total; });
            xScale.domain(data.map(function(d) { return parseDate(d.date); }));
            yScale.domain([0, d3.max(layers[layers.length - 1], function(d) { return d[0] + d[1]; }) ]).nice();

        var layer = svg.selectAll(".layer")
            .data(layers)
            .enter().append("g")
            .attr("class", "layer")
            .style("fill", function(d, i) { return color(i); });

          layer.selectAll("rect")
              .data(function(d) { return d; })
            .enter().append("rect")
        .attr('class', 'bar')
              .attr("x", function(d) { return xScale(parseDate(d.data.date)); })
              .attr("y", function(d) { return yScale(d[1]); })
              .attr("height", function(d) { return yScale(d[0]) - yScale(d[1]) -1; })
              .attr("width", xScale.bandwidth())
        .on('click', function(d, i) {
          d3.selectAll('.bar').classed('selected', false);
          d3.select(this).classed('selected', true);
        });

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

            svg.append("g")
            .attr("class", "axis axis--y")
            .attr("transform", "translate(0,0)")
            .call(yAxis);                           
    }
}
var data = [
{"date":"4/1854","total":45,"disease":12,"wounds":14,"other":25},
{"date":"5/1854","total":23,"disease":12,"wounds":0,"other":9},
{"date":"6/1854","total":38,"disease":11,"wounds":0,"other":6},
{"date":"7/1854","total":26,"disease":11,"wounds":8,"other":7}
];
var key = ["wounds", "other", "disease"];
initStackedBarChart.draw({
    data: data,
    key: key,
    element: 'stacked-bar'
});
.axis text {
  font: 10px sans-serif;
}
.axis line,
.axis path {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}
.axis--x path {
  display: none;
}
.path-line {
  fill: none;
  stroke: yellow;
  stroke-width: 1.5px;
}
svg {
  background: #f0f0f0;
}
.selected{
  stroke:#333;
  stroke-width:2;

}