【问题标题】:Linear scale inconsistency between x/y and width/heightx/y 和宽度/高度之间的线性比例不一致
【发布时间】:2018-07-24 03:52:54
【问题描述】:

我正在使用 d3 制作条形图,但遇到了一个问题:rect 元素中的 x 值似乎与宽度值不同,同样适用于 y 和高度值。奇怪的是,我将相同的值传递给每个对应方。

我正在测试这个问题并得到奇怪的结果,如下图所示。请注意,在设置范围时 yScale 正在反转。我的期望是矩形的四个角应该接触四个圆,但事实并非如此。这种行为有什么原因吗?

图片:

我的代码:

const xMax = dataset.length-1;
const yMax = d3.max(dataset, (d)=> d[1]);

const xScale = d3.scaleLinear()
                 .domain([0, xMax])
                 .range([padding, width-padding]);
const yScale = d3.scaleLinear()
                 .domain([0, yMax])
                 .range([height-padding,padding]);


svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('rect')
  .style('fill', 'none')
  .style('stroke', 'black')
  .style('stroke-width', 2)
  .attr('x', xScale(0))
  .attr('y', yScale(yMax))
  .attr('width', xScale(xMax))
  .attr('height', yScale(yMax));

【问题讨论】:

  • “奇怪的是,我将相同的值传递给每个对应方。”。不,你不是:你将xScale(0) 传递给x 位置,并将xScale(xMax) 传递给宽度。这里没有错或不一致。如果你想让矩形进入 4 个圆圈,它必须是:.attr('x', xScale(0)).attr('y', yScale(yMax)).attr('width', xScale(xMax) - padding).attr('height', yScale(0) - padding);
  • 或者,更习惯用法:.attr('x', xScale(0)).attr('y', yScale(yMax)).attr('width', xScale(xMax) - xScale(0)).attr('height', yScale(0) - yScale(yMax));
  • @GerardoFurtado 我明白了,感谢您的回答,对不起,我用错了。它现在有效,但我仍然不明白为什么需要减去填充。为什么不设置从paddingwidth - padding 的范围使xScale(xMax) 的值与width - padding 相同?
  • @GerardoFurtado 实际上,你知道吗。我想我现在明白了。谢谢:)
  • 好,你看到矩形的右端不对应圆圈x的位置了吗?您必须减去矩形的 x 位置才能得到它。我给你写了一个正确的答案。

标签: d3.js svg scale


【解决方案1】:

矩形没有到达 SVG 中的四个点(四个圆)的原因是:矩形的结束位置是它的宽度 加上 x (初始位置。垂直刻度也是如此。

现在,你有这个:

const svg = d3.select("svg");
const xMax = 280,
  yMax = 130,
  padding = 20,
  width = 300,
  height = 150;

const xScale = d3.scaleLinear()
  .domain([0, xMax])
  .range([padding, width - padding]);
const yScale = d3.scaleLinear()
  .domain([0, yMax])
  .range([height - padding, padding]);

svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('rect')
  .style('fill', 'none')
  .style('stroke', 'black')
  .style('stroke-width', 2)
  .attr('x', xScale(0))
  .attr('y', yScale(yMax))
  .attr('width', xScale(xMax))
  .attr('height', yScale(yMax));
svg {
  background-color: wheat;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

那么,如果右侧的圆圈位于xScale(xMax),为什么矩形不结束于右侧的圆圈?因为你必须从宽度中减去矩形的x 位置,才能得到这个:

rectangle's x + rectangle's width = circle's centre

而且,如前所述,矩形的高度也是如此。

话虽如此,这是工作演示:

const svg = d3.select("svg");
const xMax = 280,
  yMax = 130,
  padding = 20,
  width = 300,
  height = 150;

const xScale = d3.scaleLinear()
  .domain([0, xMax])
  .range([padding, width - padding]);
const yScale = d3.scaleLinear()
  .domain([0, yMax])
  .range([height - padding, padding]);

svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(0))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(xMax))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('circle')
  .attr('cx', xScale(0))
  .attr('cy', yScale(yMax))
  .attr('r', 10);
svg.append('rect')
  .style('fill', 'none')
  .style('stroke', 'black')
  .style('stroke-width', 2)
  .attr('x', xScale(0))
  .attr('y', yScale(yMax))
  .attr('width', xScale(xMax) - xScale(0))
  .attr('height', yScale(0) - yScale(yMax));
svg {
  background-color: wheat;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

【讨论】:

  • 感谢您的回答!只是为了向可能有类似误解的其他人澄清这个问题,我的问题主要是规模函数的工作原理。我希望xScale(xMax) 等于缩放区域的宽度,但实际上它的行为更像是一个持有一个等于 svg 坐标的数字的变量,由于填充,它大于所需的宽度。这在倒置的 Y 轴上更为明显,其中 yScale(0) 实际上拥有比 yScale(yMax) 更大的数值,因为 scale 函数引用了非倒置的 y 坐标。我说的对吗?
  • 实际上,不:xScale(xMax) 完全正确 width - padding。问题是,由于矩形从padding 开始,它将在padding + width - padding 结束,即width。你看到了吗?
  • 好的,我明白了。我的意思是,我一开始以为xScale(xMax)的值是在缩放区域的上下文中,但实际上是在整个svg区域的上下文中。
  • 哦,现在我明白了。是的,但更好的是说规模不在任何情况下!它只是一个将域映射到范围的函数。看看我的答案,它有一个规模的数学解释:stackoverflow.com/a/40539729/5768908
猜你喜欢
  • 1970-01-01
  • 2012-06-24
  • 2011-12-22
  • 2014-07-14
  • 1970-01-01
  • 2020-09-14
  • 2019-12-29
  • 2016-05-15
  • 2018-02-07
相关资源
最近更新 更多