| 
/* 
 | 
* Licensed to the Apache Software Foundation (ASF) under one 
 | 
* or more contributor license agreements.  See the NOTICE file 
 | 
* distributed with this work for additional information 
 | 
* regarding copyright ownership.  The ASF licenses this file 
 | 
* to you under the Apache License, Version 2.0 (the 
 | 
* "License"); you may not use this file except in compliance 
 | 
* with the License.  You may obtain a copy of the License at 
 | 
* 
 | 
*   http://www.apache.org/licenses/LICENSE-2.0 
 | 
* 
 | 
* Unless required by applicable law or agreed to in writing, 
 | 
* software distributed under the License is distributed on an 
 | 
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 | 
* KIND, either express or implied.  See the License for the 
 | 
* specific language governing permissions and limitations 
 | 
* under the License. 
 | 
*/ 
 | 
  
 | 
  
 | 
/** 
 | 
 * AUTO-GENERATED FILE. DO NOT MODIFY. 
 | 
 */ 
 | 
  
 | 
/* 
 | 
* Licensed to the Apache Software Foundation (ASF) under one 
 | 
* or more contributor license agreements.  See the NOTICE file 
 | 
* distributed with this work for additional information 
 | 
* regarding copyright ownership.  The ASF licenses this file 
 | 
* to you under the Apache License, Version 2.0 (the 
 | 
* "License"); you may not use this file except in compliance 
 | 
* with the License.  You may obtain a copy of the License at 
 | 
* 
 | 
*   http://www.apache.org/licenses/LICENSE-2.0 
 | 
* 
 | 
* Unless required by applicable law or agreed to in writing, 
 | 
* software distributed under the License is distributed on an 
 | 
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 | 
* KIND, either express or implied.  See the License for the 
 | 
* specific language governing permissions and limitations 
 | 
* under the License. 
 | 
*/ 
 | 
import * as zrUtil from 'zrender/lib/core/util.js'; 
 | 
import * as textContain from 'zrender/lib/contain/text.js'; 
 | 
import { makeInner } from '../util/model.js'; 
 | 
import { makeLabelFormatter, getOptionCategoryInterval, shouldShowAllLabels } from './axisHelper.js'; 
 | 
var inner = makeInner(); 
 | 
function tickValuesToNumbers(axis, values) { 
 | 
  var nums = zrUtil.map(values, function (val) { 
 | 
    return axis.scale.parse(val); 
 | 
  }); 
 | 
  if (axis.type === 'time' && nums.length > 0) { 
 | 
    // Time axis needs duplicate first/last tick (see TimeScale.getTicks()) 
 | 
    // The first and last tick/label don't get drawn 
 | 
    nums.sort(); 
 | 
    nums.unshift(nums[0]); 
 | 
    nums.push(nums[nums.length - 1]); 
 | 
  } 
 | 
  return nums; 
 | 
} 
 | 
export function createAxisLabels(axis) { 
 | 
  var custom = axis.getLabelModel().get('customValues'); 
 | 
  if (custom) { 
 | 
    var labelFormatter_1 = makeLabelFormatter(axis); 
 | 
    var extent_1 = axis.scale.getExtent(); 
 | 
    var tickNumbers = tickValuesToNumbers(axis, custom); 
 | 
    var ticks = zrUtil.filter(tickNumbers, function (val) { 
 | 
      return val >= extent_1[0] && val <= extent_1[1]; 
 | 
    }); 
 | 
    return { 
 | 
      labels: zrUtil.map(ticks, function (numval) { 
 | 
        var tick = { 
 | 
          value: numval 
 | 
        }; 
 | 
        return { 
 | 
          formattedLabel: labelFormatter_1(tick), 
 | 
          rawLabel: axis.scale.getLabel(tick), 
 | 
          tickValue: numval 
 | 
        }; 
 | 
      }) 
 | 
    }; 
 | 
  } 
 | 
  // Only ordinal scale support tick interval 
 | 
  return axis.type === 'category' ? makeCategoryLabels(axis) : makeRealNumberLabels(axis); 
 | 
} 
 | 
/** 
 | 
 * @param {module:echats/coord/Axis} axis 
 | 
 * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea. 
 | 
 * @return {Object} { 
 | 
 *     ticks: Array.<number> 
 | 
 *     tickCategoryInterval: number 
 | 
 * } 
 | 
 */ 
 | 
export function createAxisTicks(axis, tickModel) { 
 | 
  var custom = axis.getTickModel().get('customValues'); 
 | 
  if (custom) { 
 | 
    var extent_2 = axis.scale.getExtent(); 
 | 
    var tickNumbers = tickValuesToNumbers(axis, custom); 
 | 
    return { 
 | 
      ticks: zrUtil.filter(tickNumbers, function (val) { 
 | 
        return val >= extent_2[0] && val <= extent_2[1]; 
 | 
      }) 
 | 
    }; 
 | 
  } 
 | 
  // Only ordinal scale support tick interval 
 | 
  return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : { 
 | 
    ticks: zrUtil.map(axis.scale.getTicks(), function (tick) { 
 | 
      return tick.value; 
 | 
    }) 
 | 
  }; 
 | 
} 
 | 
function makeCategoryLabels(axis) { 
 | 
  var labelModel = axis.getLabelModel(); 
 | 
  var result = makeCategoryLabelsActually(axis, labelModel); 
 | 
  return !labelModel.get('show') || axis.scale.isBlank() ? { 
 | 
    labels: [], 
 | 
    labelCategoryInterval: result.labelCategoryInterval 
 | 
  } : result; 
 | 
} 
 | 
function makeCategoryLabelsActually(axis, labelModel) { 
 | 
  var labelsCache = getListCache(axis, 'labels'); 
 | 
  var optionLabelInterval = getOptionCategoryInterval(labelModel); 
 | 
  var result = listCacheGet(labelsCache, optionLabelInterval); 
 | 
  if (result) { 
 | 
    return result; 
 | 
  } 
 | 
  var labels; 
 | 
  var numericLabelInterval; 
 | 
  if (zrUtil.isFunction(optionLabelInterval)) { 
 | 
    labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval); 
 | 
  } else { 
 | 
    numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis) : optionLabelInterval; 
 | 
    labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval); 
 | 
  } 
 | 
  // Cache to avoid calling interval function repeatedly. 
 | 
  return listCacheSet(labelsCache, optionLabelInterval, { 
 | 
    labels: labels, 
 | 
    labelCategoryInterval: numericLabelInterval 
 | 
  }); 
 | 
} 
 | 
function makeCategoryTicks(axis, tickModel) { 
 | 
  var ticksCache = getListCache(axis, 'ticks'); 
 | 
  var optionTickInterval = getOptionCategoryInterval(tickModel); 
 | 
  var result = listCacheGet(ticksCache, optionTickInterval); 
 | 
  if (result) { 
 | 
    return result; 
 | 
  } 
 | 
  var ticks; 
 | 
  var tickCategoryInterval; 
 | 
  // Optimize for the case that large category data and no label displayed, 
 | 
  // we should not return all ticks. 
 | 
  if (!tickModel.get('show') || axis.scale.isBlank()) { 
 | 
    ticks = []; 
 | 
  } 
 | 
  if (zrUtil.isFunction(optionTickInterval)) { 
 | 
    ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true); 
 | 
  } 
 | 
  // Always use label interval by default despite label show. Consider this 
 | 
  // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows 
 | 
  // labels. `splitLine` and `axisTick` should be consistent in this case. 
 | 
  else if (optionTickInterval === 'auto') { 
 | 
    var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel()); 
 | 
    tickCategoryInterval = labelsResult.labelCategoryInterval; 
 | 
    ticks = zrUtil.map(labelsResult.labels, function (labelItem) { 
 | 
      return labelItem.tickValue; 
 | 
    }); 
 | 
  } else { 
 | 
    tickCategoryInterval = optionTickInterval; 
 | 
    ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true); 
 | 
  } 
 | 
  // Cache to avoid calling interval function repeatedly. 
 | 
  return listCacheSet(ticksCache, optionTickInterval, { 
 | 
    ticks: ticks, 
 | 
    tickCategoryInterval: tickCategoryInterval 
 | 
  }); 
 | 
} 
 | 
function makeRealNumberLabels(axis) { 
 | 
  var ticks = axis.scale.getTicks(); 
 | 
  var labelFormatter = makeLabelFormatter(axis); 
 | 
  return { 
 | 
    labels: zrUtil.map(ticks, function (tick, idx) { 
 | 
      return { 
 | 
        level: tick.level, 
 | 
        formattedLabel: labelFormatter(tick, idx), 
 | 
        rawLabel: axis.scale.getLabel(tick), 
 | 
        tickValue: tick.value 
 | 
      }; 
 | 
    }) 
 | 
  }; 
 | 
} 
 | 
function getListCache(axis, prop) { 
 | 
  // Because key can be a function, and cache size always is small, we use array cache. 
 | 
  return inner(axis)[prop] || (inner(axis)[prop] = []); 
 | 
} 
 | 
function listCacheGet(cache, key) { 
 | 
  for (var i = 0; i < cache.length; i++) { 
 | 
    if (cache[i].key === key) { 
 | 
      return cache[i].value; 
 | 
    } 
 | 
  } 
 | 
} 
 | 
function listCacheSet(cache, key, value) { 
 | 
  cache.push({ 
 | 
    key: key, 
 | 
    value: value 
 | 
  }); 
 | 
  return value; 
 | 
} 
 | 
function makeAutoCategoryInterval(axis) { 
 | 
  var result = inner(axis).autoInterval; 
 | 
  return result != null ? result : inner(axis).autoInterval = axis.calculateCategoryInterval(); 
 | 
} 
 | 
/** 
 | 
 * Calculate interval for category axis ticks and labels. 
 | 
 * To get precise result, at least one of `getRotate` and `isHorizontal` 
 | 
 * should be implemented in axis. 
 | 
 */ 
 | 
export function calculateCategoryInterval(axis) { 
 | 
  var params = fetchAutoCategoryIntervalCalculationParams(axis); 
 | 
  var labelFormatter = makeLabelFormatter(axis); 
 | 
  var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI; 
 | 
  var ordinalScale = axis.scale; 
 | 
  var ordinalExtent = ordinalScale.getExtent(); 
 | 
  // Providing this method is for optimization: 
 | 
  // avoid generating a long array by `getTicks` 
 | 
  // in large category data case. 
 | 
  var tickCount = ordinalScale.count(); 
 | 
  if (ordinalExtent[1] - ordinalExtent[0] < 1) { 
 | 
    return 0; 
 | 
  } 
 | 
  var step = 1; 
 | 
  // Simple optimization. Empirical value: tick count should less than 40. 
 | 
  if (tickCount > 40) { 
 | 
    step = Math.max(1, Math.floor(tickCount / 40)); 
 | 
  } 
 | 
  var tickValue = ordinalExtent[0]; 
 | 
  var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue); 
 | 
  var unitW = Math.abs(unitSpan * Math.cos(rotation)); 
 | 
  var unitH = Math.abs(unitSpan * Math.sin(rotation)); 
 | 
  var maxW = 0; 
 | 
  var maxH = 0; 
 | 
  // Caution: Performance sensitive for large category data. 
 | 
  // Consider dataZoom, we should make appropriate step to avoid O(n) loop. 
 | 
  for (; tickValue <= ordinalExtent[1]; tickValue += step) { 
 | 
    var width = 0; 
 | 
    var height = 0; 
 | 
    // Not precise, do not consider align and vertical align 
 | 
    // and each distance from axis line yet. 
 | 
    var rect = textContain.getBoundingRect(labelFormatter({ 
 | 
      value: tickValue 
 | 
    }), params.font, 'center', 'top'); 
 | 
    // Magic number 
 | 
    width = rect.width * 1.3; 
 | 
    height = rect.height * 1.3; 
 | 
    // Min size, void long loop. 
 | 
    maxW = Math.max(maxW, width, 7); 
 | 
    maxH = Math.max(maxH, height, 7); 
 | 
  } 
 | 
  var dw = maxW / unitW; 
 | 
  var dh = maxH / unitH; 
 | 
  // 0/0 is NaN, 1/0 is Infinity. 
 | 
  isNaN(dw) && (dw = Infinity); 
 | 
  isNaN(dh) && (dh = Infinity); 
 | 
  var interval = Math.max(0, Math.floor(Math.min(dw, dh))); 
 | 
  var cache = inner(axis.model); 
 | 
  var axisExtent = axis.getExtent(); 
 | 
  var lastAutoInterval = cache.lastAutoInterval; 
 | 
  var lastTickCount = cache.lastTickCount; 
 | 
  // Use cache to keep interval stable while moving zoom window, 
 | 
  // otherwise the calculated interval might jitter when the zoom 
 | 
  // window size is close to the interval-changing size. 
 | 
  // For example, if all of the axis labels are `a, b, c, d, e, f, g`. 
 | 
  // The jitter will cause that sometimes the displayed labels are 
 | 
  // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1). 
 | 
  if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 
 | 
  // Always choose the bigger one, otherwise the critical 
 | 
  // point is not the same when zooming in or zooming out. 
 | 
  && lastAutoInterval > interval 
 | 
  // If the axis change is caused by chart resize, the cache should not 
 | 
  // be used. Otherwise some hidden labels might not be shown again. 
 | 
  && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) { 
 | 
    interval = lastAutoInterval; 
 | 
  } 
 | 
  // Only update cache if cache not used, otherwise the 
 | 
  // changing of interval is too insensitive. 
 | 
  else { 
 | 
    cache.lastTickCount = tickCount; 
 | 
    cache.lastAutoInterval = interval; 
 | 
    cache.axisExtent0 = axisExtent[0]; 
 | 
    cache.axisExtent1 = axisExtent[1]; 
 | 
  } 
 | 
  return interval; 
 | 
} 
 | 
function fetchAutoCategoryIntervalCalculationParams(axis) { 
 | 
  var labelModel = axis.getLabelModel(); 
 | 
  return { 
 | 
    axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0, 
 | 
    labelRotate: labelModel.get('rotate') || 0, 
 | 
    font: labelModel.getFont() 
 | 
  }; 
 | 
} 
 | 
function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) { 
 | 
  var labelFormatter = makeLabelFormatter(axis); 
 | 
  var ordinalScale = axis.scale; 
 | 
  var ordinalExtent = ordinalScale.getExtent(); 
 | 
  var labelModel = axis.getLabelModel(); 
 | 
  var result = []; 
 | 
  // TODO: axisType: ordinalTime, pick the tick from each month/day/year/... 
 | 
  var step = Math.max((categoryInterval || 0) + 1, 1); 
 | 
  var startTick = ordinalExtent[0]; 
 | 
  var tickCount = ordinalScale.count(); 
 | 
  // Calculate start tick based on zero if possible to keep label consistent 
 | 
  // while zooming and moving while interval > 0. Otherwise the selection 
 | 
  // of displayable ticks and symbols probably keep changing. 
 | 
  // 3 is empirical value. 
 | 
  if (startTick !== 0 && step > 1 && tickCount / step > 2) { 
 | 
    startTick = Math.round(Math.ceil(startTick / step) * step); 
 | 
  } 
 | 
  // (1) Only add min max label here but leave overlap checking 
 | 
  // to render stage, which also ensure the returned list 
 | 
  // suitable for splitLine and splitArea rendering. 
 | 
  // (2) Scales except category always contain min max label so 
 | 
  // do not need to perform this process. 
 | 
  var showAllLabel = shouldShowAllLabels(axis); 
 | 
  var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel; 
 | 
  var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel; 
 | 
  if (includeMinLabel && startTick !== ordinalExtent[0]) { 
 | 
    addItem(ordinalExtent[0]); 
 | 
  } 
 | 
  // Optimize: avoid generating large array by `ordinalScale.getTicks()`. 
 | 
  var tickValue = startTick; 
 | 
  for (; tickValue <= ordinalExtent[1]; tickValue += step) { 
 | 
    addItem(tickValue); 
 | 
  } 
 | 
  if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) { 
 | 
    addItem(ordinalExtent[1]); 
 | 
  } 
 | 
  function addItem(tickValue) { 
 | 
    var tickObj = { 
 | 
      value: tickValue 
 | 
    }; 
 | 
    result.push(onlyTick ? tickValue : { 
 | 
      formattedLabel: labelFormatter(tickObj), 
 | 
      rawLabel: ordinalScale.getLabel(tickObj), 
 | 
      tickValue: tickValue 
 | 
    }); 
 | 
  } 
 | 
  return result; 
 | 
} 
 | 
function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { 
 | 
  var ordinalScale = axis.scale; 
 | 
  var labelFormatter = makeLabelFormatter(axis); 
 | 
  var result = []; 
 | 
  zrUtil.each(ordinalScale.getTicks(), function (tick) { 
 | 
    var rawLabel = ordinalScale.getLabel(tick); 
 | 
    var tickValue = tick.value; 
 | 
    if (categoryInterval(tick.value, rawLabel)) { 
 | 
      result.push(onlyTick ? tickValue : { 
 | 
        formattedLabel: labelFormatter(tick), 
 | 
        rawLabel: rawLabel, 
 | 
        tickValue: tickValue 
 | 
      }); 
 | 
    } 
 | 
  }); 
 | 
  return result; 
 | 
} 
 |