|   | 
| /* | 
| * 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 numberUtil from '../../util/number.js'; | 
| import sliderMove from '../helper/sliderMove.js'; | 
| import { unionAxisExtentFromData } from '../../coord/axisHelper.js'; | 
| import { ensureScaleRawExtentInfo } from '../../coord/scaleRawExtentInfo.js'; | 
| import { getAxisMainType, isCoordSupported } from './helper.js'; | 
| import { SINGLE_REFERRING } from '../../util/model.js'; | 
| var each = zrUtil.each; | 
| var asc = numberUtil.asc; | 
| /** | 
|  * Operate single axis. | 
|  * One axis can only operated by one axis operator. | 
|  * Different dataZoomModels may be defined to operate the same axis. | 
|  * (i.e. 'inside' data zoom and 'slider' data zoom components) | 
|  * So dataZoomModels share one axisProxy in that case. | 
|  */ | 
| var AxisProxy = /** @class */function () { | 
|   function AxisProxy(dimName, axisIndex, dataZoomModel, ecModel) { | 
|     this._dimName = dimName; | 
|     this._axisIndex = axisIndex; | 
|     this.ecModel = ecModel; | 
|     this._dataZoomModel = dataZoomModel; | 
|     // /** | 
|     //  * @readOnly | 
|     //  * @private | 
|     //  */ | 
|     // this.hasSeriesStacked; | 
|   } | 
|   /** | 
|    * Whether the axisProxy is hosted by dataZoomModel. | 
|    */ | 
|   AxisProxy.prototype.hostedBy = function (dataZoomModel) { | 
|     return this._dataZoomModel === dataZoomModel; | 
|   }; | 
|   /** | 
|    * @return Value can only be NaN or finite value. | 
|    */ | 
|   AxisProxy.prototype.getDataValueWindow = function () { | 
|     return this._valueWindow.slice(); | 
|   }; | 
|   /** | 
|    * @return {Array.<number>} | 
|    */ | 
|   AxisProxy.prototype.getDataPercentWindow = function () { | 
|     return this._percentWindow.slice(); | 
|   }; | 
|   AxisProxy.prototype.getTargetSeriesModels = function () { | 
|     var seriesModels = []; | 
|     this.ecModel.eachSeries(function (seriesModel) { | 
|       if (isCoordSupported(seriesModel)) { | 
|         var axisMainType = getAxisMainType(this._dimName); | 
|         var axisModel = seriesModel.getReferringComponents(axisMainType, SINGLE_REFERRING).models[0]; | 
|         if (axisModel && this._axisIndex === axisModel.componentIndex) { | 
|           seriesModels.push(seriesModel); | 
|         } | 
|       } | 
|     }, this); | 
|     return seriesModels; | 
|   }; | 
|   AxisProxy.prototype.getAxisModel = function () { | 
|     return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex); | 
|   }; | 
|   AxisProxy.prototype.getMinMaxSpan = function () { | 
|     return zrUtil.clone(this._minMaxSpan); | 
|   }; | 
|   /** | 
|    * Only calculate by given range and this._dataExtent, do not change anything. | 
|    */ | 
|   AxisProxy.prototype.calculateDataWindow = function (opt) { | 
|     var dataExtent = this._dataExtent; | 
|     var axisModel = this.getAxisModel(); | 
|     var scale = axisModel.axis.scale; | 
|     var rangePropMode = this._dataZoomModel.getRangePropMode(); | 
|     var percentExtent = [0, 100]; | 
|     var percentWindow = []; | 
|     var valueWindow = []; | 
|     var hasPropModeValue; | 
|     each(['start', 'end'], function (prop, idx) { | 
|       var boundPercent = opt[prop]; | 
|       var boundValue = opt[prop + 'Value']; | 
|       // Notice: dataZoom is based either on `percentProp` ('start', 'end') or | 
|       // on `valueProp` ('startValue', 'endValue'). (They are based on the data extent | 
|       // but not min/max of axis, which will be calculated by data window then). | 
|       // The former one is suitable for cases that a dataZoom component controls multiple | 
|       // axes with different unit or extent, and the latter one is suitable for accurate | 
|       // zoom by pixel (e.g., in dataZoomSelect). | 
|       // we use `getRangePropMode()` to mark which prop is used. `rangePropMode` is updated | 
|       // only when setOption or dispatchAction, otherwise it remains its original value. | 
|       // (Why not only record `percentProp` and always map to `valueProp`? Because | 
|       // the map `valueProp` -> `percentProp` -> `valueProp` probably not the original | 
|       // `valueProp`. consider two axes constrolled by one dataZoom. They have different | 
|       // data extent. All of values that are overflow the `dataExtent` will be calculated | 
|       // to percent '100%'). | 
|       if (rangePropMode[idx] === 'percent') { | 
|         boundPercent == null && (boundPercent = percentExtent[idx]); | 
|         // Use scale.parse to math round for category or time axis. | 
|         boundValue = scale.parse(numberUtil.linearMap(boundPercent, percentExtent, dataExtent)); | 
|       } else { | 
|         hasPropModeValue = true; | 
|         boundValue = boundValue == null ? dataExtent[idx] : scale.parse(boundValue); | 
|         // Calculating `percent` from `value` may be not accurate, because | 
|         // This calculation can not be inversed, because all of values that | 
|         // are overflow the `dataExtent` will be calculated to percent '100%' | 
|         boundPercent = numberUtil.linearMap(boundValue, dataExtent, percentExtent); | 
|       } | 
|       // valueWindow[idx] = round(boundValue); | 
|       // percentWindow[idx] = round(boundPercent); | 
|       // fallback to extent start/end when parsed value or percent is invalid | 
|       valueWindow[idx] = boundValue == null || isNaN(boundValue) ? dataExtent[idx] : boundValue; | 
|       percentWindow[idx] = boundPercent == null || isNaN(boundPercent) ? percentExtent[idx] : boundPercent; | 
|     }); | 
|     asc(valueWindow); | 
|     asc(percentWindow); | 
|     // The windows from user calling of `dispatchAction` might be out of the extent, | 
|     // or do not obey the `min/maxSpan`, `min/maxValueSpan`. But we don't restrict window | 
|     // by `zoomLock` here, because we see `zoomLock` just as a interaction constraint, | 
|     // where API is able to initialize/modify the window size even though `zoomLock` | 
|     // specified. | 
|     var spans = this._minMaxSpan; | 
|     hasPropModeValue ? restrictSet(valueWindow, percentWindow, dataExtent, percentExtent, false) : restrictSet(percentWindow, valueWindow, percentExtent, dataExtent, true); | 
|     function restrictSet(fromWindow, toWindow, fromExtent, toExtent, toValue) { | 
|       var suffix = toValue ? 'Span' : 'ValueSpan'; | 
|       sliderMove(0, fromWindow, fromExtent, 'all', spans['min' + suffix], spans['max' + suffix]); | 
|       for (var i = 0; i < 2; i++) { | 
|         toWindow[i] = numberUtil.linearMap(fromWindow[i], fromExtent, toExtent, true); | 
|         toValue && (toWindow[i] = scale.parse(toWindow[i])); | 
|       } | 
|     } | 
|     return { | 
|       valueWindow: valueWindow, | 
|       percentWindow: percentWindow | 
|     }; | 
|   }; | 
|   /** | 
|    * Notice: reset should not be called before series.restoreData() is called, | 
|    * so it is recommended to be called in "process stage" but not "model init | 
|    * stage". | 
|    */ | 
|   AxisProxy.prototype.reset = function (dataZoomModel) { | 
|     if (dataZoomModel !== this._dataZoomModel) { | 
|       return; | 
|     } | 
|     var targetSeries = this.getTargetSeriesModels(); | 
|     // Culculate data window and data extent, and record them. | 
|     this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries); | 
|     // `calculateDataWindow` uses min/maxSpan. | 
|     this._updateMinMaxSpan(); | 
|     var dataWindow = this.calculateDataWindow(dataZoomModel.settledOption); | 
|     this._valueWindow = dataWindow.valueWindow; | 
|     this._percentWindow = dataWindow.percentWindow; | 
|     // Update axis setting then. | 
|     this._setAxisModel(); | 
|   }; | 
|   AxisProxy.prototype.filterData = function (dataZoomModel, api) { | 
|     if (dataZoomModel !== this._dataZoomModel) { | 
|       return; | 
|     } | 
|     var axisDim = this._dimName; | 
|     var seriesModels = this.getTargetSeriesModels(); | 
|     var filterMode = dataZoomModel.get('filterMode'); | 
|     var valueWindow = this._valueWindow; | 
|     if (filterMode === 'none') { | 
|       return; | 
|     } | 
|     // FIXME | 
|     // Toolbox may has dataZoom injected. And if there are stacked bar chart | 
|     // with NaN data, NaN will be filtered and stack will be wrong. | 
|     // So we need to force the mode to be set empty. | 
|     // In fect, it is not a big deal that do not support filterMode-'filter' | 
|     // when using toolbox#dataZoom, utill tooltip#dataZoom support "single axis | 
|     // selection" some day, which might need "adapt to data extent on the | 
|     // otherAxis", which is disabled by filterMode-'empty'. | 
|     // But currently, stack has been fixed to based on value but not index, | 
|     // so this is not an issue any more. | 
|     // let otherAxisModel = this.getOtherAxisModel(); | 
|     // if (dataZoomModel.get('$fromToolbox') | 
|     //     && otherAxisModel | 
|     //     && otherAxisModel.hasSeriesStacked | 
|     // ) { | 
|     //     filterMode = 'empty'; | 
|     // } | 
|     // TODO | 
|     // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet. | 
|     each(seriesModels, function (seriesModel) { | 
|       var seriesData = seriesModel.getData(); | 
|       var dataDims = seriesData.mapDimensionsAll(axisDim); | 
|       if (!dataDims.length) { | 
|         return; | 
|       } | 
|       if (filterMode === 'weakFilter') { | 
|         var store_1 = seriesData.getStore(); | 
|         var dataDimIndices_1 = zrUtil.map(dataDims, function (dim) { | 
|           return seriesData.getDimensionIndex(dim); | 
|         }, seriesData); | 
|         seriesData.filterSelf(function (dataIndex) { | 
|           var leftOut; | 
|           var rightOut; | 
|           var hasValue; | 
|           for (var i = 0; i < dataDims.length; i++) { | 
|             var value = store_1.get(dataDimIndices_1[i], dataIndex); | 
|             var thisHasValue = !isNaN(value); | 
|             var thisLeftOut = value < valueWindow[0]; | 
|             var thisRightOut = value > valueWindow[1]; | 
|             if (thisHasValue && !thisLeftOut && !thisRightOut) { | 
|               return true; | 
|             } | 
|             thisHasValue && (hasValue = true); | 
|             thisLeftOut && (leftOut = true); | 
|             thisRightOut && (rightOut = true); | 
|           } | 
|           // If both left out and right out, do not filter. | 
|           return hasValue && leftOut && rightOut; | 
|         }); | 
|       } else { | 
|         each(dataDims, function (dim) { | 
|           if (filterMode === 'empty') { | 
|             seriesModel.setData(seriesData = seriesData.map(dim, function (value) { | 
|               return !isInWindow(value) ? NaN : value; | 
|             })); | 
|           } else { | 
|             var range = {}; | 
|             range[dim] = valueWindow; | 
|             // console.time('select'); | 
|             seriesData.selectRange(range); | 
|             // console.timeEnd('select'); | 
|           } | 
|         }); | 
|       } | 
|       each(dataDims, function (dim) { | 
|         seriesData.setApproximateExtent(valueWindow, dim); | 
|       }); | 
|     }); | 
|     function isInWindow(value) { | 
|       return value >= valueWindow[0] && value <= valueWindow[1]; | 
|     } | 
|   }; | 
|   AxisProxy.prototype._updateMinMaxSpan = function () { | 
|     var minMaxSpan = this._minMaxSpan = {}; | 
|     var dataZoomModel = this._dataZoomModel; | 
|     var dataExtent = this._dataExtent; | 
|     each(['min', 'max'], function (minMax) { | 
|       var percentSpan = dataZoomModel.get(minMax + 'Span'); | 
|       var valueSpan = dataZoomModel.get(minMax + 'ValueSpan'); | 
|       valueSpan != null && (valueSpan = this.getAxisModel().axis.scale.parse(valueSpan)); | 
|       // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan | 
|       if (valueSpan != null) { | 
|         percentSpan = numberUtil.linearMap(dataExtent[0] + valueSpan, dataExtent, [0, 100], true); | 
|       } else if (percentSpan != null) { | 
|         valueSpan = numberUtil.linearMap(percentSpan, [0, 100], dataExtent, true) - dataExtent[0]; | 
|       } | 
|       minMaxSpan[minMax + 'Span'] = percentSpan; | 
|       minMaxSpan[minMax + 'ValueSpan'] = valueSpan; | 
|     }, this); | 
|   }; | 
|   AxisProxy.prototype._setAxisModel = function () { | 
|     var axisModel = this.getAxisModel(); | 
|     var percentWindow = this._percentWindow; | 
|     var valueWindow = this._valueWindow; | 
|     if (!percentWindow) { | 
|       return; | 
|     } | 
|     // [0, 500]: arbitrary value, guess axis extent. | 
|     var precision = numberUtil.getPixelPrecision(valueWindow, [0, 500]); | 
|     precision = Math.min(precision, 20); | 
|     // For value axis, if min/max/scale are not set, we just use the extent obtained | 
|     // by series data, which may be a little different from the extent calculated by | 
|     // `axisHelper.getScaleExtent`. But the different just affects the experience a | 
|     // little when zooming. So it will not be fixed until some users require it strongly. | 
|     var rawExtentInfo = axisModel.axis.scale.rawExtentInfo; | 
|     if (percentWindow[0] !== 0) { | 
|       rawExtentInfo.setDeterminedMinMax('min', +valueWindow[0].toFixed(precision)); | 
|     } | 
|     if (percentWindow[1] !== 100) { | 
|       rawExtentInfo.setDeterminedMinMax('max', +valueWindow[1].toFixed(precision)); | 
|     } | 
|     rawExtentInfo.freeze(); | 
|   }; | 
|   return AxisProxy; | 
| }(); | 
| function calculateDataExtent(axisProxy, axisDim, seriesModels) { | 
|   var dataExtent = [Infinity, -Infinity]; | 
|   each(seriesModels, function (seriesModel) { | 
|     unionAxisExtentFromData(dataExtent, seriesModel.getData(), axisDim); | 
|   }); | 
|   // It is important to get "consistent" extent when more then one axes is | 
|   // controlled by a `dataZoom`, otherwise those axes will not be synchronized | 
|   // when zooming. But it is difficult to know what is "consistent", considering | 
|   // axes have different type or even different meanings (For example, two | 
|   // time axes are used to compare data of the same date in different years). | 
|   // So basically dataZoom just obtains extent by series.data (in category axis | 
|   // extent can be obtained from axis.data). | 
|   // Nevertheless, user can set min/max/scale on axes to make extent of axes | 
|   // consistent. | 
|   var axisModel = axisProxy.getAxisModel(); | 
|   var rawExtentResult = ensureScaleRawExtentInfo(axisModel.axis.scale, axisModel, dataExtent).calculate(); | 
|   return [rawExtentResult.min, rawExtentResult.max]; | 
| } | 
| export default AxisProxy; |