Repository: mermaid-js/mermaid
File: packages/mermaid/src/diagrams/gantt/ganttRenderer.js (JavaScript)

Code before:
      .tickFormat(timeFormat(axisFormat));

    const reTickInterval = /^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/;
    const resultTickInterval = reTickInterval.exec(
      diagObj.db.getTickInterval() || conf.tickInterval
    );

    if (resultTickInterval !== null) {
      const every = parseInt(resultTickInterval[1], 10);
      const interval = resultTickInterval[2];
      const weekday = diagObj.db.getWeekday() || conf.weekday;

      // Get the time domain to check tick count
      const domain = timeScale.domain();
      const minTime = domain[0];
      const maxTime = domain[1];
      const estimatedTicks = getEstimatedTickCount(minTime, maxTime, every, interval);

      if (estimatedTicks > MAX_TICK_COUNT) {
        log.warn(
          `The tick interval "${every}${interval}" would generate ${estimatedTicks} ticks, ` +
            `which exceeds the maximum allowed (${MAX_TICK_COUNT}). ` +
            `This may indicate an invalid date or time range. Skipping custom tick interval.`
        );
        // D3 using its default automatic tick generation
      } else {
        switch (interval) {
          case 'millisecond':
            bottomXAxis.ticks(timeMillisecond.every(every));
            break;
          case 'second':
            bottomXAxis.ticks(timeSecond.every(every));
            break;
          case 'minute':
            bottomXAxis.ticks(timeMinute.every(every));
            break;
          case 'hour':
            bottomXAxis.ticks(timeHour.every(every));
            break;
          case 'day':
            bottomXAxis.ticks(timeDay.every(every));
            break;
          case 'week':
            bottomXAxis.ticks(mapWeekdayToTimeFunction[weekday].every(every));
            break;
          case 'month':
            bottomXAxis.ticks(timeMonth.every(every));
            break;
        }
      }
    }

Review comment (refactor):
The time domain retrieval and tick estimation logic is duplicated between the bottom X axis (lines 656-668) and top X axis (lines 718-724). Consider extracting this validation logic into a reusable helper function to improve maintainability and reduce code duplication.

For example:
```javascript
function shouldApplyCustomTicks(timeScale, every, interval) {
  const domain = timeScale.domain();
  const estimatedTicks = getEstimatedTickCount(domain[0], domain[1], every, interval);
  
  if (estimatedTicks > MAX_TICK_COUNT) {
    log.warn(
      `The tick interval "${every}${interval}" would generate ${estimatedTicks} ticks, ` +
        `which exceeds the maximum allowed (${MAX_TICK_COUNT}). ` +
        `This may indicate an invalid date or time range. Skipping custom tick interval.`
    );
    return false;
  }
  return true;
}
```
```suggestion
      // Use helper to check if custom ticks should be applied
      if (shouldApplyCustomTicks(timeScale, every, interval)) {
```

Code after:
    } else {
      axisFormat = conf.axisFormat ?? '%Y-%m-%d';
    }

    let bottomXAxis = axisBottom(timeScale)
      .tickSize(-h + theTopPad + conf.gridLineStartPadding)
      .tickFormat(timeFormat(axisFormat));

    const reTickInterval = /^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/;
    const resultTickInterval = reTickInterval.exec(
      diagObj.db.getTickInterval() || conf.tickInterval
    );

    if (resultTickInterval !== null) {
      const every = parseInt(resultTickInterval[1], 10);
      if (isNaN(every) || every <= 0) {
        log.warn(
          `Invalid tick interval value: "${resultTickInterval[1]}". Skipping custom tick interval.`
        );
        // Skip applying custom ticks
      } else {
        const interval = resultTickInterval[2];
        const weekday = diagObj.db.getWeekday() || conf.weekday;

        // Get the time domain to check tick count
        const domain = timeScale.domain();
        const minTime = domain[0];
        const maxTime = domain[1];
        const estimatedTicks = getEstimatedTickCount(minTime, maxTime, every, interval);

        if (estimatedTicks > MAX_TICK_COUNT) {
          log.warn(
            `The tick interval "${every}${interval}" would generate ${estimatedTicks} ticks, ` +
              `which exceeds the maximum allowed (${MAX_TICK_COUNT}). ` +
              `This may indicate an invalid date or time range. Skipping custom tick interval.`
          );
          // D3 will use its default automatic tick generation
        } else {
          switch (interval) {
            case 'millisecond':
              bottomXAxis.ticks(timeMillisecond.every(every));
              break;
            case 'second':
              bottomXAxis.ticks(timeSecond.every(every));
              break;
            case 'minute':
              bottomXAxis.ticks(timeMinute.every(every));
              break;
            case 'hour':
              bottomXAxis.ticks(timeHour.every(every));
              break;