| 
/* 
 | 
* 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 OrdinalScale from '../scale/Ordinal.js'; 
 | 
import IntervalScale from '../scale/Interval.js'; 
 | 
import Scale from '../scale/Scale.js'; 
 | 
import { prepareLayoutBarSeries, makeColumnLayout, retrieveColumnLayout } from '../layout/barGrid.js'; 
 | 
import BoundingRect from 'zrender/lib/core/BoundingRect.js'; 
 | 
import TimeScale from '../scale/Time.js'; 
 | 
import LogScale from '../scale/Log.js'; 
 | 
import { getStackedDimension } from '../data/helper/dataStackHelper.js'; 
 | 
import { ensureScaleRawExtentInfo } from './scaleRawExtentInfo.js'; 
 | 
/** 
 | 
 * Get axis scale extent before niced. 
 | 
 * Item of returned array can only be number (including Infinity and NaN). 
 | 
 * 
 | 
 * Caution: 
 | 
 * Precondition of calling this method: 
 | 
 * The scale extent has been initialized using series data extent via 
 | 
 * `scale.setExtent` or `scale.unionExtentFromData`; 
 | 
 */ 
 | 
export function getScaleExtent(scale, model) { 
 | 
  var scaleType = scale.type; 
 | 
  var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate(); 
 | 
  scale.setBlank(rawExtentResult.isBlank); 
 | 
  var min = rawExtentResult.min; 
 | 
  var max = rawExtentResult.max; 
 | 
  // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis 
 | 
  // is base axis 
 | 
  // FIXME 
 | 
  // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly. 
 | 
  // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent? 
 | 
  //     Should not depend on series type `bar`? 
 | 
  // (3) Fix that might overlap when using dataZoom. 
 | 
  // (4) Consider other chart types using `barGrid`? 
 | 
  // See #6728, #4862, `test/bar-overflow-time-plot.html` 
 | 
  var ecModel = model.ecModel; 
 | 
  if (ecModel && scaleType === 'time' /* || scaleType === 'interval' */) { 
 | 
    var barSeriesModels = prepareLayoutBarSeries('bar', ecModel); 
 | 
    var isBaseAxisAndHasBarSeries_1 = false; 
 | 
    zrUtil.each(barSeriesModels, function (seriesModel) { 
 | 
      isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis; 
 | 
    }); 
 | 
    if (isBaseAxisAndHasBarSeries_1) { 
 | 
      // Calculate placement of bars on axis. TODO should be decoupled 
 | 
      // with barLayout 
 | 
      var barWidthAndOffset = makeColumnLayout(barSeriesModels); 
 | 
      // Adjust axis min and max to account for overflow 
 | 
      var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset); 
 | 
      min = adjustedScale.min; 
 | 
      max = adjustedScale.max; 
 | 
    } 
 | 
  } 
 | 
  return { 
 | 
    extent: [min, max], 
 | 
    // "fix" means "fixed", the value should not be 
 | 
    // changed in the subsequent steps. 
 | 
    fixMin: rawExtentResult.minFixed, 
 | 
    fixMax: rawExtentResult.maxFixed 
 | 
  }; 
 | 
} 
 | 
function adjustScaleForOverflow(min, max, model, 
 | 
// Only support cartesian coord yet. 
 | 
barWidthAndOffset) { 
 | 
  // Get Axis Length 
 | 
  var axisExtent = model.axis.getExtent(); 
 | 
  var axisLength = Math.abs(axisExtent[1] - axisExtent[0]); 
 | 
  // Get bars on current base axis and calculate min and max overflow 
 | 
  var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis); 
 | 
  if (barsOnCurrentAxis === undefined) { 
 | 
    return { 
 | 
      min: min, 
 | 
      max: max 
 | 
    }; 
 | 
  } 
 | 
  var minOverflow = Infinity; 
 | 
  zrUtil.each(barsOnCurrentAxis, function (item) { 
 | 
    minOverflow = Math.min(item.offset, minOverflow); 
 | 
  }); 
 | 
  var maxOverflow = -Infinity; 
 | 
  zrUtil.each(barsOnCurrentAxis, function (item) { 
 | 
    maxOverflow = Math.max(item.offset + item.width, maxOverflow); 
 | 
  }); 
 | 
  minOverflow = Math.abs(minOverflow); 
 | 
  maxOverflow = Math.abs(maxOverflow); 
 | 
  var totalOverFlow = minOverflow + maxOverflow; 
 | 
  // Calculate required buffer based on old range and overflow 
 | 
  var oldRange = max - min; 
 | 
  var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength; 
 | 
  var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange; 
 | 
  max += overflowBuffer * (maxOverflow / totalOverFlow); 
 | 
  min -= overflowBuffer * (minOverflow / totalOverFlow); 
 | 
  return { 
 | 
    min: min, 
 | 
    max: max 
 | 
  }; 
 | 
} 
 | 
// Precondition of calling this method: 
 | 
// The scale extent has been initialized using series data extent via 
 | 
// `scale.setExtent` or `scale.unionExtentFromData`; 
 | 
export function niceScaleExtent(scale, inModel) { 
 | 
  var model = inModel; 
 | 
  var extentInfo = getScaleExtent(scale, model); 
 | 
  var extent = extentInfo.extent; 
 | 
  var splitNumber = model.get('splitNumber'); 
 | 
  if (scale instanceof LogScale) { 
 | 
    scale.base = model.get('logBase'); 
 | 
  } 
 | 
  var scaleType = scale.type; 
 | 
  var interval = model.get('interval'); 
 | 
  var isIntervalOrTime = scaleType === 'interval' || scaleType === 'time'; 
 | 
  scale.setExtent(extent[0], extent[1]); 
 | 
  scale.calcNiceExtent({ 
 | 
    splitNumber: splitNumber, 
 | 
    fixMin: extentInfo.fixMin, 
 | 
    fixMax: extentInfo.fixMax, 
 | 
    minInterval: isIntervalOrTime ? model.get('minInterval') : null, 
 | 
    maxInterval: isIntervalOrTime ? model.get('maxInterval') : null 
 | 
  }); 
 | 
  // If some one specified the min, max. And the default calculated interval 
 | 
  // is not good enough. He can specify the interval. It is often appeared 
 | 
  // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard 
 | 
  // to be 60. 
 | 
  // FIXME 
 | 
  if (interval != null) { 
 | 
    scale.setInterval && scale.setInterval(interval); 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * @param axisType Default retrieve from model.type 
 | 
 */ 
 | 
export function createScaleByModel(model, axisType) { 
 | 
  axisType = axisType || model.get('type'); 
 | 
  if (axisType) { 
 | 
    switch (axisType) { 
 | 
      // Buildin scale 
 | 
      case 'category': 
 | 
        return new OrdinalScale({ 
 | 
          ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(), 
 | 
          extent: [Infinity, -Infinity] 
 | 
        }); 
 | 
      case 'time': 
 | 
        return new TimeScale({ 
 | 
          locale: model.ecModel.getLocaleModel(), 
 | 
          useUTC: model.ecModel.get('useUTC') 
 | 
        }); 
 | 
      default: 
 | 
        // case 'value'/'interval', 'log', or others. 
 | 
        return new (Scale.getClass(axisType) || IntervalScale)(); 
 | 
    } 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * Check if the axis cross 0 
 | 
 */ 
 | 
export function ifAxisCrossZero(axis) { 
 | 
  var dataExtent = axis.scale.getExtent(); 
 | 
  var min = dataExtent[0]; 
 | 
  var max = dataExtent[1]; 
 | 
  return !(min > 0 && max > 0 || min < 0 && max < 0); 
 | 
} 
 | 
/** 
 | 
 * @param axis 
 | 
 * @return Label formatter function. 
 | 
 *         param: {number} tickValue, 
 | 
 *         param: {number} idx, the index in all ticks. 
 | 
 *                         If category axis, this param is not required. 
 | 
 *         return: {string} label string. 
 | 
 */ 
 | 
export function makeLabelFormatter(axis) { 
 | 
  var labelFormatter = axis.getLabelModel().get('formatter'); 
 | 
  var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null; 
 | 
  if (axis.scale.type === 'time') { 
 | 
    return function (tpl) { 
 | 
      return function (tick, idx) { 
 | 
        return axis.scale.getFormattedLabel(tick, idx, tpl); 
 | 
      }; 
 | 
    }(labelFormatter); 
 | 
  } else if (zrUtil.isString(labelFormatter)) { 
 | 
    return function (tpl) { 
 | 
      return function (tick) { 
 | 
        // For category axis, get raw value; for numeric axis, 
 | 
        // get formatted label like '1,333,444'. 
 | 
        var label = axis.scale.getLabel(tick); 
 | 
        var text = tpl.replace('{value}', label != null ? label : ''); 
 | 
        return text; 
 | 
      }; 
 | 
    }(labelFormatter); 
 | 
  } else if (zrUtil.isFunction(labelFormatter)) { 
 | 
    return function (cb) { 
 | 
      return function (tick, idx) { 
 | 
        // The original intention of `idx` is "the index of the tick in all ticks". 
 | 
        // But the previous implementation of category axis do not consider the 
 | 
        // `axisLabel.interval`, which cause that, for example, the `interval` is 
 | 
        // `1`, then the ticks "name5", "name7", "name9" are displayed, where the 
 | 
        // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep 
 | 
        // the definition here for back compatibility. 
 | 
        if (categoryTickStart != null) { 
 | 
          idx = tick.value - categoryTickStart; 
 | 
        } 
 | 
        return cb(getAxisRawValue(axis, tick), idx, tick.level != null ? { 
 | 
          level: tick.level 
 | 
        } : null); 
 | 
      }; 
 | 
    }(labelFormatter); 
 | 
  } else { 
 | 
    return function (tick) { 
 | 
      return axis.scale.getLabel(tick); 
 | 
    }; 
 | 
  } 
 | 
} 
 | 
export function getAxisRawValue(axis, tick) { 
 | 
  // In category axis with data zoom, tick is not the original 
 | 
  // index of axis.data. So tick should not be exposed to user 
 | 
  // in category axis. 
 | 
  return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value; 
 | 
} 
 | 
/** 
 | 
 * @param axis 
 | 
 * @return Be null/undefined if no labels. 
 | 
 */ 
 | 
export function estimateLabelUnionRect(axis) { 
 | 
  var axisModel = axis.model; 
 | 
  var scale = axis.scale; 
 | 
  if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) { 
 | 
    return; 
 | 
  } 
 | 
  var realNumberScaleTicks; 
 | 
  var tickCount; 
 | 
  var categoryScaleExtent = scale.getExtent(); 
 | 
  // Optimize for large category data, avoid call `getTicks()`. 
 | 
  if (scale instanceof OrdinalScale) { 
 | 
    tickCount = scale.count(); 
 | 
  } else { 
 | 
    realNumberScaleTicks = scale.getTicks(); 
 | 
    tickCount = realNumberScaleTicks.length; 
 | 
  } 
 | 
  var axisLabelModel = axis.getLabelModel(); 
 | 
  var labelFormatter = makeLabelFormatter(axis); 
 | 
  var rect; 
 | 
  var step = 1; 
 | 
  // Simple optimization for large amount of labels 
 | 
  if (tickCount > 40) { 
 | 
    step = Math.ceil(tickCount / 40); 
 | 
  } 
 | 
  for (var i = 0; i < tickCount; i += step) { 
 | 
    var tick = realNumberScaleTicks ? realNumberScaleTicks[i] : { 
 | 
      value: categoryScaleExtent[0] + i 
 | 
    }; 
 | 
    var label = labelFormatter(tick, i); 
 | 
    var unrotatedSingleRect = axisLabelModel.getTextRect(label); 
 | 
    var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0); 
 | 
    rect ? rect.union(singleRect) : rect = singleRect; 
 | 
  } 
 | 
  return rect; 
 | 
} 
 | 
function rotateTextRect(textRect, rotate) { 
 | 
  var rotateRadians = rotate * Math.PI / 180; 
 | 
  var beforeWidth = textRect.width; 
 | 
  var beforeHeight = textRect.height; 
 | 
  var afterWidth = beforeWidth * Math.abs(Math.cos(rotateRadians)) + Math.abs(beforeHeight * Math.sin(rotateRadians)); 
 | 
  var afterHeight = beforeWidth * Math.abs(Math.sin(rotateRadians)) + Math.abs(beforeHeight * Math.cos(rotateRadians)); 
 | 
  var rotatedRect = new BoundingRect(textRect.x, textRect.y, afterWidth, afterHeight); 
 | 
  return rotatedRect; 
 | 
} 
 | 
/** 
 | 
 * @param model axisLabelModel or axisTickModel 
 | 
 * @return {number|String} Can be null|'auto'|number|function 
 | 
 */ 
 | 
export function getOptionCategoryInterval(model) { 
 | 
  var interval = model.get('interval'); 
 | 
  return interval == null ? 'auto' : interval; 
 | 
} 
 | 
/** 
 | 
 * Set `categoryInterval` as 0 implicitly indicates that 
 | 
 * show all labels regardless of overlap. 
 | 
 * @param {Object} axis axisModel.axis 
 | 
 */ 
 | 
export function shouldShowAllLabels(axis) { 
 | 
  return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0; 
 | 
} 
 | 
export function getDataDimensionsOnAxis(data, axisDim) { 
 | 
  // Remove duplicated dat dimensions caused by `getStackedDimension`. 
 | 
  var dataDimMap = {}; 
 | 
  // Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult'). 
 | 
  // PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since 
 | 
  // there has been stacked result dim? 
 | 
  zrUtil.each(data.mapDimensionsAll(axisDim), function (dataDim) { 
 | 
    // For example, the extent of the original dimension 
 | 
    // is [0.1, 0.5], the extent of the `stackResultDimension` 
 | 
    // is [7, 9], the final extent should NOT include [0.1, 0.5], 
 | 
    // because there is no graphic corresponding to [0.1, 0.5]. 
 | 
    // See the case in `test/area-stack.html` `main1`, where area line 
 | 
    // stack needs `yAxis` not start from 0. 
 | 
    dataDimMap[getStackedDimension(data, dataDim)] = true; 
 | 
  }); 
 | 
  return zrUtil.keys(dataDimMap); 
 | 
} 
 | 
export function unionAxisExtentFromData(dataExtent, data, axisDim) { 
 | 
  if (data) { 
 | 
    zrUtil.each(getDataDimensionsOnAxis(data, axisDim), function (dim) { 
 | 
      var seriesExtent = data.getApproximateExtent(dim); 
 | 
      seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]); 
 | 
      seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]); 
 | 
    }); 
 | 
  } 
 | 
} 
 |