'use strict';

const legendInputProcessor = require('./legend-input-processor-1e53e5bc.js');
const array = require('./array-249289f2.js');

/* eslint-disable jsdoc/require-param-type, jsdoc/require-returns-type, jsdoc/require-param, jsdoc/require-returns */
/**
 * D3 Scale Polyfill - Lightweight scale generators for chart axes.
 *
 * This is a drop-in replacement for d3-scale, implementing only the methods
 * used in the Vega chart rendering system: scaleLinear, scaleTime, and scaleBand.
 *
 * @see VD-5022 - [Zero Dependencies] remove d3 dependency
 */
// ─── Linear Scale ───────────────────────────────────────────────────
/**
 * A linear scale that maps a continuous numeric domain to a continuous range.
 * Mimics d3.scaleLinear().
 */
class LinearScale {
  constructor() {
    this._domain = [0, 1];
    this._range = [0, 1];
  }
  /**
   * Maps a domain value to its corresponding range value via linear interpolation.
   *
   * @param value - Input domain value.
   * @returns Interpolated range value.
   */
  call(value) {
    const v = Number(value);
    const d0 = this._domain[0];
    const d1 = this._domain[1];
    const r0 = this._range[0];
    const r1 = this._range[1];
    if (d1 === d0)
      return (r0 + r1) / 2;
    return r0 + ((v - d0) / (d1 - d0)) * (r1 - r0);
  }
  /**
   * Gets or sets the domain.
   *
   * @param [domain] - Optional new domain [min, max].
   * @returns The current domain (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  domain(domain) {
    if (domain === undefined)
      return [...this._domain];
    this._domain = domain.map(Number);
    return this;
  }
  /**
   * Gets or sets the range.
   *
   * @param [range] - Optional new range [min, max].
   * @returns The current range (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  range(range) {
    if (range === undefined)
      return [...this._range];
    this._range = [...range];
    return this;
  }
  /**
   * Generates approximately `count` nicely-spaced tick values within the domain.
   *
   * @param [count] - Desired number of ticks (default 10).
   * @returns Array of tick values.
   */
  ticks(count = 10) {
    const [d0, d1] = this._domain;
    const step = tickStep(d0, d1, count);
    if (step === 0 || !isFinite(step))
      return [d0];
    const start = Math.ceil(d0 / step) * step;
    const stop = Math.floor(d1 / step) * step;
    const ticks = [];
    for (let v = start; v <= stop + step / 2; v += step) {
      ticks.push(Math.round(v * 1e12) / 1e12);
    }
    return ticks;
  }
  /**
   * Returns a tick format function that uses comma grouping and Unicode minus.
   *
   * @param count - Desired number of ticks (used to compute precision).
   * @returns A function that converts tick values to formatted strings.
   */
  tickFormat(count = 10) {
    const [d0, d1] = this._domain;
    const step = tickStep(d0, d1, count);
    const precision = step > 0 ? Math.max(0, -Math.floor(Math.log10(step))) : 0;
    return (d) => formatFixedD3(Number(d), precision);
  }
  /**
   * Returns a copy of this scale.
   *
   * @returns A new LinearScale with the same domain and range.
   */
  copy() {
    const s = new LinearScale();
    s._domain = [...this._domain];
    s._range = [...this._range];
    return s;
  }
}
/**
 * Computes a nice tick step size for the given domain and tick count.
 * Follows d3's tick step algorithm.
 *
 * @param start - Domain start.
 * @param stop - Domain stop.
 * @param count - Desired number of ticks.
 * @returns Step size.
 */
function tickStep(start, stop, count) {
  const span = Math.abs(stop - start);
  let step = Math.pow(10, Math.floor(Math.log10(span / count)));
  const error = span / count / step;
  if (error >= 7.5)
    step *= 10;
  else if (error >= 3.5)
    step *= 5;
  else if (error >= 1.5)
    step *= 2;
  return stop < start ? -step : step;
}
/**
 * Adds comma grouping to an integer string (e.g., "1000" → "1,000").
 */
function addCommaGrouping(intStr) {
  const len = intStr.length;
  if (len <= 3)
    return intStr;
  let result = '';
  for (let i = 0; i < len; i++) {
    if (i > 0 && (len - i) % 3 === 0)
      result += ',';
    result += intStr[i];
  }
  return result;
}
/**
 * Formats a number with comma grouping and unicode minus, matching d3-format's ",f" specifier.
 */
function formatFixedD3(value, precision) {
  const abs = Math.abs(value);
  let formatted;
  if (precision <= 0) {
    formatted = addCommaGrouping(String(Math.round(abs)));
  }
  else {
    const fixed = abs.toFixed(precision);
    const dotIndex = fixed.indexOf('.');
    formatted = addCommaGrouping(fixed.substring(0, dotIndex)) + fixed.substring(dotIndex);
  }
  if (value < 0) {
    return '\u2212' + formatted;
  }
  return formatted;
}
/**
 * Creates a linear scale. Mimics d3.scaleLinear().
 *
 * @returns A callable linear scale function with chaining methods.
 */
function scaleLinear() {
  const scale = new LinearScale();
  /* eslint-disable jsdoc/require-jsdoc */
  const fn = Object.assign((value) => scale.call(value), {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    domain: (d) => {
      if (d === undefined)
        return scale.domain();
      scale.domain(d);
      return fn;
    },
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    range: (r) => {
      if (r === undefined)
        return scale.range();
      scale.range(r);
      return fn;
    },
    ticks: (count) => scale.ticks(count),
    tickFormat: (...args) => scale.tickFormat(args[0]),
    copy: () => {
      const copied = scale.copy();
      return scaleLinearFromInstance(copied);
    },
    bandwidth: () => 0,
  });
  /* eslint-enable jsdoc/require-jsdoc */
  return fn;
}
/**
 * Creates a callable linear scale from an existing LinearScale instance.
 */
function scaleLinearFromInstance(scale) {
  /* eslint-disable jsdoc/require-jsdoc */
  const fn = Object.assign((value) => scale.call(value), {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    domain: (d) => {
      if (d === undefined)
        return scale.domain();
      scale.domain(d);
      return fn;
    },
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    range: (r) => {
      if (r === undefined)
        return scale.range();
      scale.range(r);
      return fn;
    },
    ticks: (count) => scale.ticks(count),
    tickFormat: (...args) => scale.tickFormat(args[0]),
    copy: () => {
      const copied = scale.copy();
      return scaleLinearFromInstance(copied);
    },
    bandwidth: () => 0,
  });
  /* eslint-enable jsdoc/require-jsdoc */
  return fn;
}
// ─── Time Scale ─────────────────────────────────────────────────────
/**
 * Ceils a date to the next boundary of the given time unit and step.
 * E.g., unit='month', step=1 → first of the next month.
 */
function timeScaleCeil(date, unit, step) {
  const d = new Date(date);
  switch (unit) {
    case 'second':
      d.setMilliseconds(0);
      d.setSeconds(Math.ceil(d.getSeconds() / step) * step);
      if (d.getTime() <= date.getTime())
        d.setSeconds(d.getSeconds() + step);
      break;
    case 'minute':
      d.setSeconds(0, 0);
      d.setMinutes(Math.ceil(d.getMinutes() / step) * step);
      if (d.getTime() <= date.getTime())
        d.setMinutes(d.getMinutes() + step);
      break;
    case 'hour':
      d.setMinutes(0, 0, 0);
      d.setHours(Math.ceil(d.getHours() / step) * step);
      if (d.getTime() <= date.getTime())
        d.setHours(d.getHours() + step);
      break;
    case 'day':
      d.setHours(0, 0, 0, 0);
      if (d.getTime() <= date.getTime())
        d.setDate(d.getDate() + step);
      break;
    case 'week':
      d.setHours(0, 0, 0, 0);
      d.setDate(d.getDate() - d.getDay()); // floor to Sunday
      if (d.getTime() <= date.getTime())
        d.setDate(d.getDate() + 7 * step);
      break;
    case 'month':
      d.setDate(1);
      d.setHours(0, 0, 0, 0);
      if (d.getTime() <= date.getTime())
        d.setMonth(d.getMonth() + step);
      break;
    case 'year':
      d.setMonth(0, 1);
      d.setHours(0, 0, 0, 0);
      if (d.getTime() <= date.getTime())
        d.setFullYear(d.getFullYear() + step);
      break;
  }
  return d;
}
/**
 * Advances a date by the given time unit and step.
 */
function timeScaleAdvance(date, unit, step) {
  const d = new Date(date);
  switch (unit) {
    case 'second':
      d.setSeconds(d.getSeconds() + step);
      break;
    case 'minute':
      d.setMinutes(d.getMinutes() + step);
      break;
    case 'hour':
      d.setHours(d.getHours() + step);
      break;
    case 'day':
      d.setDate(d.getDate() + step);
      break;
    case 'week':
      d.setDate(d.getDate() + 7 * step);
      break;
    case 'month':
      d.setMonth(d.getMonth() + step);
      break;
    case 'year':
      d.setFullYear(d.getFullYear() + step);
      break;
  }
  return d;
}
/**
 * A time scale that maps a Date domain to a continuous numeric range.
 * Mimics d3.scaleTime().
 */
class TimeScale {
  constructor() {
    this._domain = [new Date(2000, 0, 1), new Date(2000, 0, 2)];
    this._range = [0, 1];
  }
  /**
   * Maps a Date domain value to a range value.
   *
   * @param value - Input Date value.
   * @returns Interpolated range value.
   */
  call(value) {
    const t = value instanceof Date ? value.getTime() : Number(value);
    const t0 = this._domain[0].getTime();
    const t1 = this._domain[1].getTime();
    const r0 = this._range[0];
    const r1 = this._range[1];
    if (t1 === t0)
      return r0;
    return r0 + ((t - t0) / (t1 - t0)) * (r1 - r0);
  }
  /**
   * Gets or sets the domain.
   *
   * @param domain - Optional new domain [minDate, maxDate].
   * @returns The current domain (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  domain(domain) {
    if (domain === undefined)
      return [...this._domain];
    this._domain = domain.map((d) => new Date(d));
    return this;
  }
  /**
   * Gets or sets the range.
   *
   * @param range - Optional new range [min, max].
   * @returns The current range (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  range(range) {
    if (range === undefined)
      return [...this._range];
    this._range = [...range];
    return this;
  }
  /**
   * Generates nicely-spaced tick Date values within the domain.
   * Picks the best time interval (year, month, week, day, hour, minute, second)
   * to produce approximately `count` ticks.
   *
   * @param count - Desired number of ticks (default 10).
   * @returns Array of Date tick values.
   */
  ticks(count = 10) {
    const start = this._domain[0].getTime();
    const end = this._domain[1].getTime();
    const duration = Math.abs(end - start);
    if (duration === 0)
      return [new Date(start)];
    // Time intervals in ms with candidate step multipliers
    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const WEEK = 7 * DAY;
    const MONTH = 30.44 * DAY;
    const YEAR = 365.25 * DAY;
    const intervals = [
      { unit: 'second', ms: SECOND, steps: [1, 5, 15, 30] },
      { unit: 'minute', ms: MINUTE, steps: [1, 5, 15, 30] },
      { unit: 'hour', ms: HOUR, steps: [1, 3, 6, 12] },
      { unit: 'day', ms: DAY, steps: [1, 2] },
      { unit: 'week', ms: WEEK, steps: [1] },
      { unit: 'month', ms: MONTH, steps: [1, 3] },
      { unit: 'year', ms: YEAR, steps: [1, 5, 10, 25, 50, 100] },
    ];
    // Find the interval+step combo closest to the desired tick count
    let bestUnit = 'month';
    let bestStep = 1;
    let bestDiff = Infinity;
    for (const iv of intervals) {
      for (const step of iv.steps) {
        const tickCount = duration / (iv.ms * step);
        const diff = Math.abs(tickCount - count);
        if (diff < bestDiff) {
          bestDiff = diff;
          bestUnit = iv.unit;
          bestStep = step;
        }
      }
    }
    // Ceil start date to next interval boundary, then step forward
    const ticks = [];
    const startDate = new Date(start);
    const endDate = new Date(end);
    let current = timeScaleCeil(startDate, bestUnit, bestStep);
    while (current.getTime() <= endDate.getTime() && ticks.length < 200) {
      ticks.push(new Date(current));
      current = timeScaleAdvance(current, bestUnit, bestStep);
    }
    return ticks;
  }
  /**
   * Returns a tick format function for dates.
   *
   * @returns A function that formats tick values as date strings.
   */
  tickFormat() {
    return (d) => {
      if (d instanceof Date)
        return d.toLocaleDateString();
      return String(d);
    };
  }
}
/**
 * Creates a time scale. Mimics d3.scaleTime().
 *
 * @returns A callable time scale function with chaining methods.
 */
function scaleTime() {
  const scale = new TimeScale();
  /* eslint-disable jsdoc/require-jsdoc */
  const fn = Object.assign((value) => scale.call(value), {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    domain: (d) => {
      if (d === undefined)
        return scale.domain();
      scale.domain(d);
      return fn;
    },
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    range: (r) => {
      if (r === undefined)
        return scale.range();
      scale.range(r);
      return fn;
    },
    ticks: () => scale.ticks(),
    tickFormat: () => scale.tickFormat(),
    copy: () => scaleTime(),
    bandwidth: () => 0,
  });
  /* eslint-enable jsdoc/require-jsdoc */
  return fn;
}
// ─── Band Scale ─────────────────────────────────────────────────────
/**
 * A band (ordinal) scale that maps discrete domain values to equal-width bands.
 * Mimics d3.scaleBand().
 */
class BandScale {
  /**
   * Creates a new BandScale.
   *
   * @param domain - Optional initial domain values.
   * @param range - Optional initial range [min, max].
   */
  constructor(domain, range) {
    this._domain = [];
    this._range = [0, 1];
    this._padding = 0;
    if (domain)
      this._domain = [...new Set(domain)];
    if (range)
      this._range = [...range];
  }
  /**
   * Maps a domain value to the start of its band.
   *
   * @param value - Input domain value.
   * @returns The start position of the band, or undefined if not in domain.
   */
  call(value) {
    const index = this._domain.indexOf(value);
    if (index === -1)
      return undefined;
    const n = this._domain.length;
    const totalRange = this._range[1] - this._range[0];
    // d3 step formula: step = totalRange / (n + padding)
    const step = totalRange / (n + this._padding);
    // d3 centers bands: start = (range - step*(n - padding)) / 2 = step * padding
    const startOffset = step * this._padding;
    return this._range[0] + startOffset + index * step;
  }
  /**
   * Gets or sets the domain.
   *
   * @param domain - Optional new domain values.
   * @returns The current domain (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  domain(domain) {
    if (domain === undefined)
      return [...this._domain];
    this._domain = [...new Set(domain)];
    return this;
  }
  /**
   * Gets or sets the range.
   *
   * @param range - Optional new range [min, max].
   * @returns The current range (if no arg), or this for chaining.
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  range(range) {
    if (range === undefined)
      return [...this._range];
    this._range = [...range];
    return this;
  }
  /**
   * Sets the padding ratio for bands (0 to 1).
   *
   * @param padding - Padding ratio.
   * @returns This scale for chaining.
   */
  padding(padding) {
    this._padding = padding;
    return this;
  }
  /**
   * Returns the width of each band.
   *
   * @returns Band width in pixels.
   */
  bandwidth() {
    const n = this._domain.length;
    if (n === 0)
      return 0;
    const totalRange = this._range[1] - this._range[0];
    // d3 step formula: step = totalRange / (n + padding)
    const step = totalRange / (n + this._padding);
    return step * (1 - this._padding);
  }
}
/**
 * Creates a band scale. Mimics d3.scaleBand().
 *
 * @param domain - Optional initial domain values.
 * @param range - Optional initial range [min, max].
 * @returns A callable band scale function with chaining methods.
 */
function scaleBand(domain, range) {
  const scale = new BandScale(domain, range);
  /* eslint-disable jsdoc/require-jsdoc */
  const fn = Object.assign((value) => scale.call(value), {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    domain: (d) => {
      if (d === undefined)
        return scale.domain();
      scale.domain(d);
      return fn;
    },
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    range: (r) => {
      if (r === undefined)
        return scale.range();
      scale.range(r);
      return fn;
    },
    padding: (p) => {
      scale.padding(p);
      return fn;
    },
    bandwidth: () => scale.bandwidth(),
  });
  /* eslint-enable jsdoc/require-jsdoc */
  return fn;
}

/**
 * D3 Array Polyfill - Lightweight array utility functions.
 *
 * This is a drop-in replacement for d3-array, implementing only the methods
 * used in the Vega chart rendering system: min, max, extent, and map.
 *
 * @see VD-5022 - [Zero Dependencies] remove d3 dependency
 */
/**
 * Returns the minimum value in the array.
 * Mimics d3.min().
 *
 * @template T
 * @param {T[]} array - Array of values.
 * @param {Function} [accessor] - Optional accessor function.
 * @returns {number | undefined} The minimum value, or undefined for empty arrays.
 */
function min(array, accessor) {
  let result;
  for (let i = 0; i < array.length; i++) {
    const value = accessor ? accessor(array[i], i) : Number(array[i]);
    if (value != null && !Number.isNaN(value)) {
      if (result === undefined || value < result) {
        result = value;
      }
    }
  }
  return result;
}
/**
 * Returns the maximum value in the array.
 * Mimics d3.max().
 *
 * @template T
 * @param {T[]} array - Array of values.
 * @param {Function} [accessor] - Optional accessor function.
 * @returns {number | undefined} The maximum value, or undefined for empty arrays.
 */
function max(array, accessor) {
  let result;
  for (let i = 0; i < array.length; i++) {
    const value = accessor ? accessor(array[i], i) : Number(array[i]);
    if (value != null && !Number.isNaN(value)) {
      if (result === undefined || value > result) {
        result = value;
      }
    }
  }
  return result;
}
/**
 * Returns the [min, max] of the array.
 * Mimics d3.extent().
 *
 * @template T
 * @param {T[]} array - Array of values.
 * @returns {[T, T] | [undefined, undefined]} Tuple of [min, max], or [undefined, undefined] for empty arrays.
 */
function extent(array) {
  let minVal;
  let maxVal;
  for (const value of array) {
    if (value != null && value >= value) {
      if (minVal === undefined || value < minVal) {
        minVal = value;
      }
      if (maxVal === undefined || value > maxVal) {
        maxVal = value;
      }
    }
  }
  if (minVal === undefined || maxVal === undefined) {
    return [undefined, undefined];
  }
  return [minVal, maxVal];
}
/**
 * Maps each element of the array through a transform function.
 * Mimics d3.map() (the array mapping function from d3-array, not the Map collection).
 *
 * @template T
 * @template U
 * @param {T[]} array - Input array.
 * @param {Function} mapper - Transform function called with (element, index).
 * @returns {U[]} New array of transformed values.
 */
function map(array, mapper) {
  return array.map(mapper);
}

/**
 * The XAxisDrawer class extends the BaseDrawer class and draws the x-axis of a chart using the provided render options.
 */
class XAxisDrawer extends legendInputProcessor.BaseDrawer {
  /** This function adds interaction support */
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  addInteractionSupport() { }
  /**
   * This function draws the X-axis of a chart using the provided rendering options.
   */
  draw() {
    this.renderer.drawXAxis(this.options.renderOptions, this.getColorFromToken('bg-tertiary'), this.getStyleTextFromToken('v-font-field-label-sm v-text-secondary'));
  }
}

/** The YAxisDrawer class extends the BaseDrawer class and draws the Y-axis of a chart using the provided render options. */
class YAxisDrawer extends legendInputProcessor.BaseDrawer {
  /** This function adds interaction support */
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  addInteractionSupport() { }
  /**
   * The function draws the Y-axis of a chart using the provided rendering options.
   */
  draw() {
    this.renderer.drawYAxis(this.options.renderOptions, this.getColorFromToken('bg-tertiary'), this.getStyleTextFromToken('v-font-field-label-sm v-text-secondary'));
  }
}

/** The XAxisInputProcessor class generates X-axis options for a line chart based on input data and previous layout results. */
class XAxisInputProcessor {
  /**
   * This function generates X-axis options for a line chart based on input data and previous layout results.
   *
   * @param {ChartOptions<LineChartDataType>} input - An object containing chart options, including the data source, x-axis options, and
   * container element.
   * @param {LayoutProcessResultType} [previousOutput] - The optional output from the previous layout
   * process. It is of type LayoutProcessResultType and contains information about the innerWidth and
   * innerHeight of the chart container.
   * @returns {ChartExtend<AxisScale<AxisDomain>>} a ChartExtend object that contains the options for the X-axis of a line chart, including
   * the scale generated by the scaleGenerator and the axis options generated by the axisGenerator.
   */
  process(input, previousOutput) {
    const { dataSource, xAxis, container } = input;
    const { innerWidth, innerHeight } = previousOutput;
    const xAxisType = (xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) || 'value';
    const scale = this.getScale(dataSource, innerWidth, xAxisType, container.tagName === 'VEGA-LINE-CHART' ? 1 : 0.1, xAxis === null || xAxis === void 0 ? void 0 : xAxis.sorter);
    return {
      start: { x: 0, y: innerHeight },
      end: { x: innerWidth, y: innerHeight },
      tickSize: 4,
      scale: scale,
      labelFormatter: xAxis === null || xAxis === void 0 ? void 0 : xAxis.labelFormatter,
      width: innerWidth,
      height: innerHeight,
    };
  }
  /**
   * get x scale
   *
   * @param {ChartDataSourceItem[]} data data source
   * @param {number} width svg width
   * @param {ChartXAxisType} xAxisType x axis data type
   * @param {number} padding x position offset value
   * @param {(item:string,nextItem:string)=>number} sorter the sorter function using when the category type
   * @returns {AxisScale<AxisDomain>} x scale
   */
  getScale(data, width, xAxisType, padding = 0.1, sorter) {
    const flatData = array.flatNestedArray(data);
    const xData = flatData.map((item) => item.x);
    let xScale;
    if (xAxisType === 'time') {
      const ext = extent(xData);
      xScale = scaleTime()
        .domain(ext[0] !== undefined ? ext : [new Date(), new Date()])
        .range([0, width]);
    }
    else if (xAxisType === 'category') {
      xScale = scaleBand(typeof sorter === 'function' ? xData.sort(sorter) : xData, [0, width]).padding(padding);
    }
    else {
      const ext = extent(xData);
      xScale = scaleLinear()
        .domain(ext[0] !== undefined ? ext : [0, 0])
        .range([0, width]);
    }
    return xScale;
  }
}

/** The YAxisInputProcessor class generates Y-axis options for a line chart based on input data and previous layout results. */
class YAxisInputProcessor {
  /**
   * This function generates the Y-axis options for a line chart based on the input data and previous layout results.
   *
   * @param {ChartOptions<LineChartDataType>} input - An object containing the chart options and data for a line chart. It includes the
   * dataSource and yAxis properties.
   * @param {LayoutProcessResultType} [previousOutput] - The output of the previous layout process,
   * which is an object containing the innerWidth and innerHeight of the chart. This parameter is
   * optional and can be undefined if it's the first layout process.
   * @returns {ChartExtend<AxisScale<AxisDomain>>} an object of type `ChartExtend<AxisScale<AxisDomain>>`, which is the result of calling the
   * `getAxisOptions` method of the `axisGenerator` object. This object contains options for the Y-axis
   * of a line chart, including the scale used for the axis.
   */
  process(input, previousOutput) {
    const { dataSource, yAxis } = input;
    const { innerWidth, innerHeight } = previousOutput;
    const { scale, ticks } = this.getScale(dataSource, [innerHeight, 0], 4);
    return {
      start: { x: 0, y: 0 },
      end: { x: 0, y: innerHeight },
      tickSize: ticks,
      scale: scale,
      labelFormatter: yAxis === null || yAxis === void 0 ? void 0 : yAxis.labelFormatter,
      width: innerWidth,
      height: innerHeight,
    };
  }
  /**
   * get y scale
   *
   * @param {ChartDataSourceItem[]} data data source
   * @param {number[]} range svg scale range
   * @param {number} ticks the y-axis ticks
   * @returns {ScaleType}y scale
   */
  getScale(data, range, ticks) {
    var _a, _b;
    const flatData = array.flatNestedArray(data);
    const yData = flatData.map((item) => item.y).concat(0);
    let maxYData = (_a = max(yData)) !== null && _a !== void 0 ? _a : 0;
    let minYData = (_b = min(yData)) !== null && _b !== void 0 ? _b : 0;
    let yScale = scaleLinear().domain([minYData, maxYData]);
    const ticksValue = (yScale.ticks ? yScale.ticks(ticks) : []);
    const step = Math.abs(ticksValue[ticksValue.length - 1] - ticksValue[ticksValue.length - 2]);
    const ext = extent(ticksValue);
    const [minTickValue, maxTickValue] = ext[0] !== undefined ? ext : [0, 0];
    if (minYData < minTickValue) {
      minYData = minTickValue - step;
      ticks += 1;
    }
    if (maxYData > maxTickValue) {
      maxYData = maxTickValue + step;
      ticks += 1;
    }
    yScale = scaleLinear().domain([minYData, maxYData]).range(range);
    return { scale: yScale, ticks };
  }
}

exports.XAxisDrawer = XAxisDrawer;
exports.XAxisInputProcessor = XAxisInputProcessor;
exports.YAxisDrawer = YAxisDrawer;
exports.YAxisInputProcessor = YAxisInputProcessor;
exports.map = map;
