gpt4 book ai didi

javascript - 如何在使用 D3.js 放大时删除非整数刻度?

转载 作者:行者123 更新时间:2023-12-05 04:30:28 32 4
gpt4 key购买 nike

问题:我正在尝试创建一个可平移/可缩放的线性 X 轴,每个整数上都有刻度,从 0 到预定义的大数字(比如 1000,但可能更高)。显然这不会全部适合屏幕并且可读,所以我需要它离开屏幕并且可以平移。从 0 到 10 开头是可以接受的。到目前为止,我的解决方案存在很多问题,但第一个问题是,如果我放大,D3 会自动在小数位的整数之间添加刻度,以继续在屏幕上显示 10 个刻度。第二个是当我缩小时,范围将显示超过 1000。

快速说明:将要显示的数据无关紧要。无论 1000 上是否有数据点,轴都必须从 0 到 1000,因此我无法根据我的数据集确定域。

我尝试过的解决方案:

  • .ticks()。这让我可以指定我想要的刻度数。然而,这似乎将所有报价都置于指定的初始范围内。如果我将范围的宽度增加到超过 svg 大小,它会展开刻度,但不是以任何可控的方式(据我所知)。此外,我遇到了平移和缩放的性能问题。我发现这种行为很奇怪,因为如果我不指定刻度,它会产生一个无限的数字,我可以毫无延迟地平移。我假设出现滞后是因为它试图立即呈现所有 1000 个刻度,而默认的 d3.js 功能会在您滚动时动态呈现它们。这似乎是一个潜在的解决方案,但我不确定如何执行它。
  • .tickValues()。我可以提供一个 0 到 1000 的数组,这可以工作,但表现出与 .ticks() 完全相同的滞后行为。当我缩小时,这也不会动态地将刻度组合成 10 秒或 100 秒。
  • .tickFormat()。我可以运行一个函数,以便将任何非整数转换为空字符串。然而,这仍然留下了刻度线。

以下是我使用最新版本的 D3.js(7.3) 的代码的相关部分:

const height = 500
const width = 1200

const margin = {
top: 20,
right: 20,
bottom: 20,
left: 35
}

const innerWidth = width - margin.left - margin.right
const innerHeight = height - margin.top - margin.bottom


const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, innerWidth])

const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)

svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', innerWidth)
.attr('height', innerHeight)

const zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([
[0, 0],
[xScale(upperBound), 0]
])
.on('zoom', zoomed)

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)

const xAxis = d3.axisBottom()
.scale(xScale)

const xAxisG = g.append('g')
.style('clip-path', 'url(#clip)')
.attr("class", "x-axis")
.call(xAxis)
.attr('transform', `translate(0, ${innerHeight})`)

svg.call(zoom)

function zoomed(event) {
const updateX = event.transform.rescaleX(xScale)
const zx = xAxis.scale(updateX)
xAxisG.call(zx)
}

最佳答案

无需处理轴的方法,您只需选择容器组本身的刻度,移除非整数:

xAxisG.call(zx)
.selectAll(".tick")
.filter(e => e % 1)
.remove();

这里是你的代码有那个变化:

const upperBound = 1000
const height = 100
const width = 600

const margin = {
top: 20,
right: 20,
bottom: 20,
left: 35
}

const innerWidth = width - margin.left - margin.right
const innerHeight = height - margin.top - margin.bottom


const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, innerWidth])

const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)

svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', innerWidth)
.attr('height', innerHeight)

const zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([
[0, 0],
[xScale(upperBound), 0]
])
.on('zoom', zoomed)

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)

const xAxis = d3.axisBottom()
.scale(xScale)
.tickFormat(d => ~~d)

const xAxisG = g.append('g')
.style('clip-path', 'url(#clip)')
.attr("class", "x-axis")
.call(xAxis)
.attr('transform', `translate(0, ${innerHeight})`)

svg.call(zoom)

function zoomed(event) {
const updateX = event.transform.rescaleX(xScale)
const zx = xAxis.scale(updateX)
xAxisG.call(zx)
.selectAll(".tick")
.filter(e => e % 1)
.remove();
}
<script src="https://d3js.org/d3.v7.min.js"></script>
<svg></svg>

关于javascript - 如何在使用 D3.js 放大时删除非整数刻度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72078915/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com