问题:我试图创建一个可平移/可zoom 的线性X轴,每个整数上的刻度从0到预定义的大数字(比如1000,但可能更高).很明显,这些内容不能全部显示在屏幕上,也不能完全可读,所以我需要将其移出屏幕并可平移.从0到10开始是可以接受的.到目前为止,我的解决方案有很多问题,但第一个问题是,如果我放大,D3会自动在小数点处的整数之间添加刻度,以继续在屏幕上显示10个刻度.第二个是当我缩小时,显示范围将超过1000.

请注意:将显示的数据与此无关.轴必须从0到1000,无论1000上是否有数据点,因此我无法根据数据集确定域.

我try 过的解决方案:

  • .ticks().这让我可以指定所需的刻度数.然而,这似乎将所有刻度置于指定的初始范围内.如果我将范围的宽度增加到svg大小之外,它会分散刻度,但不是以任何可控的方式(据我所知).此外,我还遇到了性能问题,其中平移和zoom .我觉得这种行为很奇怪,因为如果我不指定滴答声,它会产生一个无限数,我可以毫无延迟地平移.我assume延迟发生,因为它试图立即呈现所有assume0个滴答声和默认的d3.js功能在滚动时动态呈现它们.这似乎是一个潜在的解决方案,但我不确定如何执行它.
  • .tickValues().我可以提供一个从0到1000的数组,这是可行的,但表现出与之完全相同的滞后行为.滴答声().当我缩小时,这也不会动态地将刻度组合成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)
}

推荐答案

不需要处理axis的方法,只需在容器组本身中 Select 记号,移除非整数:

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相关问答推荐

防止用户在selectizeInput中取消 Select 选项

如何在Obsidian dataview中创建进度条

colored颜色 检测JS,平均图像 colored颜色 检测JS

未捕获错误:[]:getActivePinia()被调用,但没有活动Pinia.🍍""在调用app.use(pinia)之前,您是否try 使用store ?""

如何从调整大小/zoom 的SVG路径定义新的d属性?""

S文本内容和值不必要的不同

使用领域Web SDK的Vite+Vue应用程序中的Web程序集(WASM)错误

React.Development.js和未捕获的ReferenceError:未定义useState

在验证和提交表单后使用useNavigate()进行react 重定向,使用带有加载器和操作的路由

Phaser3 preFX addGlow不支持zoom

如何通过Axios在GraphQL查询中发送数组

是否设置以JavaScript为背景的画布元素?

MUI迷你图:如何将$符号添加到MUI迷你图中的工具提示数据

使用Java脚本替换字符串中的小文本格式hashtag

在每次重新加载页面时更改指针光标

Reaction路由v6.4+数据API:重试加载程序而不显示错误

如何从嵌套的json中获取最大值

单击子按钮时将活动切换类添加到父分区

与find()方法一起使用时,Mongoose中的$or运算符没有提供所有必需的数据

在不使用AJAX的情况下将JavaScript数组值传递给Laravel控制器?