【问题标题】:Using rem with d3 (for purposes of keeping font sizes similar at different scales)将 rem 与 d3 一起使用(为了在不同比例下保持字体大小相似)
【发布时间】:2022-08-05 18:29:29
【问题描述】:

目前是第一次使用 d3 和 CSS 的中级知识。

这是code pen 我将在这个问题中引用 - 也作为堆栈 sn-p:

const padding = 30
const fakeData = [
  [0, 0],
  [100, 300],
  [300, 250],
  [500, 450]
]

function applyGraph(svg) {
  // Setup the axes
  const xScale = d3.scaleLinear()
    .range([0 + padding, 200 - padding])
    .domain([500, 0])
  const yScale = d3.scaleLinear()
    .range([0 + padding, 200 - padding])
    .domain([0, 500])
  
  const xAxis = d3.axisBottom(xScale).ticks(4)
  const yAxis = d3.axisLeft(yScale).ticks(4)
  svg.append(\'g\')
    .attr(\'class\', \'axis-rem\')
    .attr(\'transform\', `translate(0, ${200 - padding})`)
    .call(xAxis)
  svg.append(\'g\')
    .attr(\'class\', \'axis-rem\')
    .attr(\'transform\', `translate(${padding}, 0)`)
    .call(yAxis)
  
  // Plot some data
  const line = d3.line()
    .x(d => xScale(d[0]))
    .y(d => yScale(d[1]))
  
  svg.append(\'path\')
    .data([fakeData])
    .attr(\'class\', \'line-rem\')
    .attr(\'fill\', \'none\')
    .attr(\'stroke\', \'blue\')
    .attr(\'d\', line)
}

var g1 = d3.select(\"#graph1\")
var g2 = d3.select(\"#graph2\")
applyGraph(g1)
applyGraph(g2)
.line-rem {
   stroke-width: 0.4rem;
}

.axis-rem {
  font-size: 0.6rem;
}
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js\"></script>
<svg 
     id=\"graph1\"
     viewBox=\"0 0 200 200\"
     width=\"400\" 
     height=\"400\"/>
<svg 
     id=\"graph2\"
     viewBox=\"0 0 200 200\"
     width=\"200\" 
     height=\"200\"/>

我有一个函数(组件),它根据一些数据呈现一个 d3 图。此功能在许多不同大小/比例的地方重复使用。我的目标是让文本和笔画宽度保持相同的大小,而不管 SVG 缩放到的大小。

我最初的想法是使用我之前听说过的rem 单位。我的理解是,这应该使大小相对于“根元素”。然而,即使在 SVG 中将这些单位用于 stroke-widthfont-size 之后,文本和线条似乎也具有不同的大小。

两个问题:

  1. 为什么会发生这种情况?是因为“根元素”被重置为&lt;svg&gt; 标签或类似的东西吗?
  2. 如何实现创建stroke-widthfont-size 的目标(我不想硬编码一些px 值)?
  • 您的轴尺寸在applyGraph 中是固定的,但您的svg 尺寸会有所不同(尽管viewBox 尺寸不变)......有什么可以改变的?
  • @RobinMackenzie 感谢您的回复! d3 和viewBox 非常新。我假设scaleLinear().range(...) 指的是视图框的尺寸。我是否必须更改viewBox 以匹配svg 组件上的heightwidth?我愿意有一个可变大小的viewBox(尽管目前不确定它是如何工作的),因为最终我希望图表填充给定的任何水平空间。

标签: css d3.js


【解决方案1】:

关于使用widthheightviewbox herehere 有一些有用的答案。

您的较大图表已“放大”,因为相同的 200x200 坐标系在更大的 SVG 上拉伸(400x400 与 200x200)。

如果您放弃viewBox 并更改applyGraph 以识别svgwidthheight,那么您的图表将显示相同的字体和笔划宽度:

const padding = 30
const fakeData = [
  [0, 0],
  [100, 300],
  [300, 250],
  [500, 450]
]

function applyGraph(svg) {
  // get dimensions of svg
  const svgWidth = +svg.attr("width");
  const svgHeight = +svg.attr("height");

  // Setup the axes
  const xScale = d3.scaleLinear()
    .range([0 + padding, svgWidth - padding])
    .domain([500, 0])
  const yScale = d3.scaleLinear()
    .range([0 + padding, svgHeight - padding])
    .domain([0, 500])
  
  const xAxis = d3.axisBottom(xScale).ticks(4)
  const yAxis = d3.axisLeft(yScale).ticks(4)
  svg.append('g')
    .attr('class', 'axis-rem')
    .attr('transform', `translate(0, ${svgHeight - padding})`)
    .call(xAxis)
  svg.append('g')
    .attr('class', 'axis-rem')
    .attr('transform', `translate(${padding}, 0)`)
    .call(yAxis)
  
  // Plot some data
  const line = d3.line()
    .x(d => xScale(d[0]))
    .y(d => yScale(d[1]))
  
  svg.append('path')
    .data([fakeData])
    .attr('class', 'line-rem')
    .attr('fill', 'none')
    .attr('stroke', 'blue')
    .attr('d', line)
}

var g1 = d3.select("#graph1")
var g2 = d3.select("#graph2")
applyGraph(g1)
applyGraph(g2)
.line-rem {
   stroke-width: 0.4rem;
}

.axis-rem {
  font-size: 0.6rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
<svg 
     id="graph1"
     width="400" 
     height="400"/>
<svg 
     id="graph2"
     width="200" 
     height="200"/>

【讨论】:

    猜你喜欢
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    相关资源
    最近更新 更多