Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

277
Vistas
How can I remove non-integer ticks while zooming in with D3.js?

Problem: I am trying to create a pannable/zoomable Linear X axis with ticks on each integer from 0 to a predefined large number (let's say 1000 but could be much higher). Obviously this will not all fit on the screen and be readable, so I need it to go offscreen and be pannable. Starting with 0 through 10 is acceptable. There are a number of problems with my solution so far, but the first being that if I zoom in, D3 automatically adds ticks in between the integers at decimal places to continue to have 10 ticks on the screen. The second being when I zoom out, the range will display beyond 1000.

A quick note: The data that will be displayed is irrelevant. The axis has to go from 0 to 1000 regardless if there is a datapoint on 1000 or not so I cannot determine the domain based on my dataset.

Solutions I've tried:

  • .ticks(). This lets me specify the number of ticks I want. However this appears to put all the ticks into the initial range specified. If I increase the width of the range past the svg size, it spreads out the ticks, but not in any controllable way (to my knowledge). Additionally I run into performance issues where the panning and zooming. I find this behavior strange since if I don't specify ticks, it makes an infinite number I can pan through without any lag. I assume the lag occurs because it's trying to render all 1000 ticks immediately and the default d3.js functionality renders them dynamically as you scroll. This seems like a potential solution, but I'm not sure how to execute it.
  • .tickValues(). I can provide an array of 0 through 1000 and this works but exhibits the exact same lag behavior as .ticks(). This also doesn't dynamically combine ticks into 10s or 100s as I zoom out.
  • .tickFormat(). I can run a function through so that any non-integer number is converted to an empty string. However, this still leaves the tick line.

Here are the relevant parts of my code using the latest version of 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)
}

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Instead of dealing with the axis' methods, you can simply select the ticks in the container group itself, removing the non-integers:

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

Here is your code with that change:

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>

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda