javascript - 条形图中的 rangeRoundBands outerPadding 太大了

标签 javascript css d3.js

我是 D3.js 的新手,我的垂直条形图有问题。出于某种原因,当我使用 rangeRoundBands 进行缩放时,轴和条形之间的距离太大了。 在API中,是这样解释的:

enter image description here

所以问题似乎是outerPadding。但是将 outerPadding 设置为零并没有帮助。但是,当我改用 rangeBands 时,问题就消失了,条形图的位置正确,就在轴的正下方。但是我会得到这些讨厌的抗锯齿效果,所以这不是一个真正的选择。这是我的代码:

var margin = {top: 40, right: 40, bottom: 20, left: 20},
    width = 900 - margin.left - margin.right,
            height = x - margin.top - margin.bottom;

    var x = d3.scale.linear().range([0, width]);

    var y = d3.scale.ordinal().rangeRoundBands([0, height], .15, 0);

    var xAxis = d3.svg.axis()
            .scale(x)
            .orient("top");

    var xAxis2 = d3.svg.axis()
            .scale(x)
            .orient("bottom");

    var xAxis3 = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickSize(-height, 0, 0)
            .tickFormat("");

    var svg = d3.select("#plotContainer").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


    x.domain(d3.extent(data, function(d) {
        return d.size;
    })).nice();
    y.domain(data.map(function(d) {
        return d.name;
    }));

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

    svg.selectAll(".bar")
            .data(data)
            .enter().append("rect")
            .attr("class", function(d) {
                return d.size < 0 ? "bar negative" : "bar positive";
            })
            .attr("x", function(d) {
                return x(Math.min(0, d.size));
            })
            .attr("y", function(d) {
                return y(d.name);
            })
            .attr("width", function(d) {
                return Math.abs(x(d.size) - x(0));
            })
            .attr("height", y.rangeBand())
            .append("title")
            .text(function(d) {
                return "This value is " + d.name;
            });
    ;

    svg.selectAll(".bar.positive")
            .style("fill", "steelblue")
            .on("mouseover", function(d) {
                d3.select(this).style("fill", "yellow");
            })
            .on("mouseout", function(d) {
                d3.select(this).style("fill", "steelblue");
            });

    svg.selectAll(".bar.negative")
            .style("fill", "brown")
            .on("mouseover", function(d) {
                d3.select(this).style("fill", "yellow");
            })
            .on("mouseout", function(d) {
                d3.select(this).style("fill", "brown");
            });

    svg.selectAll(".axis")
            .style("fill", "none")
            .style("shape-rendering", "crispEdges")
            .style("stroke", "#000")
            .style("font", "10px sans-serif");

    svg.selectAll(".grid")
            .style("fill", "none")
            .style("stroke", "lightgrey")
            .style("opacity", "0.7");

    svg.selectAll(".grid.path")
            .style("stroke-width", "0");

编辑: 请看看这个 fiddle : http://jsfiddle.net/GUYZk/9/

我的问题在那里可以重现。您不能使用 rangeRoundBands 改变 outerPadding,而 rangeBands 表现正常。

最佳答案

TL;DR:这是数学的结果。要变通,请使用 rangeBands 布置条形,并使用 shape-rendering: crispEdges在 CSS 中将它们与像素边界对齐。


完整解释:

因为 rangeRoundBands 函数必须在提供的像素范围内均匀分布条形图 AND 它还必须提供一个整数 rangeBand,它使用 Math.floor 以切断每个连续柱的小数位。

这种额外的外部填充与更长的数据集复合的原因是因为所有这些小数像素都必须在某处结束。这个函数的作者选择在范围的开始和结束之间平均分配它们。

因为每个圆条的分数像素位于区间 (0, 1) 上,所以在每一端 glommed 的额外像素将跨越数据条计数的大约 1/4。如果有 10 个条,2-3 个额外的像素将永远不会被注意到,但如果有 100 个或更多,额外的 25+ 个像素会变得更加明显。

在 Chrome 中似乎适用于 svg:rect 的一种可能解决方案:使用 rangeBands 进行布局,然后应用 shape-rendering: crispEdges作为您的栏路径/矩形的 CSS 样式。

这就让 SVG 渲染器有责任将每个条形微调到像素边界,但它们总体上间隔更均匀,间距偶尔会出现变化以解释整个图表的错误。

就我个人而言,我使用 shape-rendering: optimizeSpeed 并让渲染代理做出必要的权衡以快速渲染(可能是分数的)条形位置。

关于javascript - 条形图中的 rangeRoundBands outerPadding 太大了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23127172/

相关文章:

javascript - JSONLoader 光线转换器和碰撞网格 - three.js

javascript - 如何从内联样式中获取百分比而不是像素的高度?

javascript - jQuery FadeIn、FadeOut 垃圾邮件 bug

javascript - 使用不同事件的相同功能

html - 如何删除 h1 上方的空格?

html - 如果不将第三个 float 推到下一行,则无法将边距添加到 .col-*-4 类

javascript - d3.js:如何用空白值的颜色填充单元格?

css - 为什么高度文本框小于按钮?

d3.js - D3 强制布局 : making pan on drag (zoom) smoother

d3.js - 如何调整画笔选择的高度