| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 | 
/** 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.*/var _config = require("../../config");var __DEV__ = _config.__DEV__;var _util = require("zrender/lib/core/util");var isObject = _util.isObject;var each = _util.each;var map = _util.map;var indexOf = _util.indexOf;var retrieve = _util.retrieve;var _layout = require("../../util/layout");var getLayoutRect = _layout.getLayoutRect;var _axisHelper = require("../../coord/axisHelper");var createScaleByModel = _axisHelper.createScaleByModel;var ifAxisCrossZero = _axisHelper.ifAxisCrossZero;var niceScaleExtent = _axisHelper.niceScaleExtent;var estimateLabelUnionRect = _axisHelper.estimateLabelUnionRect;var Cartesian2D = require("./Cartesian2D");var Axis2D = require("./Axis2D");var CoordinateSystem = require("../../CoordinateSystem");var _dataStackHelper = require("../../data/helper/dataStackHelper");var getStackedDimension = _dataStackHelper.getStackedDimension;require("./GridModel");/** 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.*//** * Grid is a region which contains at most 4 cartesian systems * * TODO Default cartesian */// Depends on GridModel, AxisModel, which performs preprocess./** * Check if the axis is used in the specified grid * @inner */function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {  return axisModel.getCoordSysModel() === gridModel;}function Grid(gridModel, ecModel, api) {  /**   * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}   * @private   */  this._coordsMap = {};  /**   * @type {Array.<module:echarts/coord/cartesian/Cartesian>}   * @private   */  this._coordsList = [];  /**   * @type {Object.<string, Array.<module:echarts/coord/cartesian/Axis2D>>}   * @private   */  this._axesMap = {};  /**   * @type {Array.<module:echarts/coord/cartesian/Axis2D>}   * @private   */  this._axesList = [];  this._initCartesian(gridModel, ecModel, api);  this.model = gridModel;}var gridProto = Grid.prototype;gridProto.type = 'grid';gridProto.axisPointerEnabled = true;gridProto.getRect = function () {  return this._rect;};gridProto.update = function (ecModel, api) {  var axesMap = this._axesMap;  this._updateScale(ecModel, this.model);  each(axesMap.x, function (xAxis) {    niceScaleExtent(xAxis.scale, xAxis.model);  });  each(axesMap.y, function (yAxis) {    niceScaleExtent(yAxis.scale, yAxis.model);  }); // Key: axisDim_axisIndex, value: boolean, whether onZero target.  var onZeroRecords = {};  each(axesMap.x, function (xAxis) {    fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);  });  each(axesMap.y, function (yAxis) {    fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);  }); // Resize again if containLabel is enabled  // FIXME It may cause getting wrong grid size in data processing stage  this.resize(this.model, api);};function fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {  axis.getAxesOnZeroOf = function () {    // TODO: onZero of multiple axes.    return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];  }; // onZero can not be enabled in these two situations:  // 1. When any other axis is a category axis.  // 2. When no axis is cross 0 point.  var otherAxes = axesMap[otherAxisDim];  var otherAxisOnZeroOf;  var axisModel = axis.model;  var onZero = axisModel.get('axisLine.onZero');  var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');  if (!onZero) {    return;  } // If target axis is specified.  if (onZeroAxisIndex != null) {    if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {      otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];    }  } else {    // Find the first available other axis.    for (var idx in otherAxes) {      if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) // Consider that two Y axes on one value axis,      // if both onZero, the two Y axes overlap.      && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) {        otherAxisOnZeroOf = otherAxes[idx];        break;      }    }  }  if (otherAxisOnZeroOf) {    onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;  }  function getOnZeroRecordKey(axis) {    return axis.dim + '_' + axis.index;  }}function canOnZeroToAxis(axis) {  return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);}/** * Resize the grid * @param {module:echarts/coord/cartesian/GridModel} gridModel * @param {module:echarts/ExtensionAPI} api */gridProto.resize = function (gridModel, api, ignoreContainLabel) {  var gridRect = getLayoutRect(gridModel.getBoxLayoutParams(), {    width: api.getWidth(),    height: api.getHeight()  });  this._rect = gridRect;  var axesList = this._axesList;  adjustAxes(); // Minus label size  if (!ignoreContainLabel && gridModel.get('containLabel')) {    each(axesList, function (axis) {      if (!axis.model.get('axisLabel.inside')) {        var labelUnionRect = estimateLabelUnionRect(axis);        if (labelUnionRect) {          var dim = axis.isHorizontal() ? 'height' : 'width';          var margin = axis.model.get('axisLabel.margin');          gridRect[dim] -= labelUnionRect[dim] + margin;          if (axis.position === 'top') {            gridRect.y += labelUnionRect.height + margin;          } else if (axis.position === 'left') {            gridRect.x += labelUnionRect.width + margin;          }        }      }    });    adjustAxes();  }  function adjustAxes() {    each(axesList, function (axis) {      var isHorizontal = axis.isHorizontal();      var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];      var idx = axis.inverse ? 1 : 0;      axis.setExtent(extent[idx], extent[1 - idx]);      updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);    });  }};/** * @param {string} axisType * @param {number} [axisIndex] */gridProto.getAxis = function (axisType, axisIndex) {  var axesMapOnDim = this._axesMap[axisType];  if (axesMapOnDim != null) {    if (axisIndex == null) {      // Find first axis      for (var name in axesMapOnDim) {        if (axesMapOnDim.hasOwnProperty(name)) {          return axesMapOnDim[name];        }      }    }    return axesMapOnDim[axisIndex];  }};/** * @return {Array.<module:echarts/coord/Axis>} */gridProto.getAxes = function () {  return this._axesList.slice();};/** * Usage: *      grid.getCartesian(xAxisIndex, yAxisIndex); *      grid.getCartesian(xAxisIndex); *      grid.getCartesian(null, yAxisIndex); *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...}); * * @param {number|Object} [xAxisIndex] * @param {number} [yAxisIndex] */gridProto.getCartesian = function (xAxisIndex, yAxisIndex) {  if (xAxisIndex != null && yAxisIndex != null) {    var key = 'x' + xAxisIndex + 'y' + yAxisIndex;    return this._coordsMap[key];  }  if (isObject(xAxisIndex)) {    yAxisIndex = xAxisIndex.yAxisIndex;    xAxisIndex = xAxisIndex.xAxisIndex;  } // When only xAxisIndex or yAxisIndex given, find its first cartesian.  for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {    if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) {      return coordList[i];    }  }};gridProto.getCartesians = function () {  return this._coordsList.slice();};/** * @implements * see {module:echarts/CoodinateSystem} */gridProto.convertToPixel = function (ecModel, finder, value) {  var target = this._findConvertTarget(ecModel, finder);  return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;};/** * @implements * see {module:echarts/CoodinateSystem} */gridProto.convertFromPixel = function (ecModel, finder, value) {  var target = this._findConvertTarget(ecModel, finder);  return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;};/** * @inner */gridProto._findConvertTarget = function (ecModel, finder) {  var seriesModel = finder.seriesModel;  var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis')[0];  var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis')[0];  var gridModel = finder.gridModel;  var coordsList = this._coordsList;  var cartesian;  var axis;  if (seriesModel) {    cartesian = seriesModel.coordinateSystem;    indexOf(coordsList, cartesian) < 0 && (cartesian = null);  } else if (xAxisModel && yAxisModel) {    cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);  } else if (xAxisModel) {    axis = this.getAxis('x', xAxisModel.componentIndex);  } else if (yAxisModel) {    axis = this.getAxis('y', yAxisModel.componentIndex);  } // Lowest priority.  else if (gridModel) {      var grid = gridModel.coordinateSystem;      if (grid === this) {        cartesian = this._coordsList[0];      }    }  return {    cartesian: cartesian,    axis: axis  };};/** * @implements * see {module:echarts/CoodinateSystem} */gridProto.containPoint = function (point) {  var coord = this._coordsList[0];  if (coord) {    return coord.containPoint(point);  }};/** * Initialize cartesian coordinate systems * @private */gridProto._initCartesian = function (gridModel, ecModel, api) {  var axisPositionUsed = {    left: false,    right: false,    top: false,    bottom: false  };  var axesMap = {    x: {},    y: {}  };  var axesCount = {    x: 0,    y: 0  }; /// Create axis  ecModel.eachComponent('xAxis', createAxisCreator('x'), this);  ecModel.eachComponent('yAxis', createAxisCreator('y'), this);  if (!axesCount.x || !axesCount.y) {    // Roll back when there no either x or y axis    this._axesMap = {};    this._axesList = [];    return;  }  this._axesMap = axesMap; /// Create cartesian2d  each(axesMap.x, function (xAxis, xAxisIndex) {    each(axesMap.y, function (yAxis, yAxisIndex) {      var key = 'x' + xAxisIndex + 'y' + yAxisIndex;      var cartesian = new Cartesian2D(key);      cartesian.grid = this;      cartesian.model = gridModel;      this._coordsMap[key] = cartesian;      this._coordsList.push(cartesian);      cartesian.addAxis(xAxis);      cartesian.addAxis(yAxis);    }, this);  }, this);  function createAxisCreator(axisType) {    return function (axisModel, idx) {      if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {        return;      }      var axisPosition = axisModel.get('position');      if (axisType === 'x') {        // Fix position        if (axisPosition !== 'top' && axisPosition !== 'bottom') {          // Default bottom of X          axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom';        }      } else {        // Fix position        if (axisPosition !== 'left' && axisPosition !== 'right') {          // Default left of Y          axisPosition = axisPositionUsed.left ? 'right' : 'left';        }      }      axisPositionUsed[axisPosition] = true;      var axis = new Axis2D(axisType, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition);      var isCategory = axis.type === 'category';      axis.onBand = isCategory && axisModel.get('boundaryGap');      axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel      axisModel.axis = axis; // Inject axisModel into axis      axis.model = axisModel; // Inject grid info axis      axis.grid = this; // Index of axis, can be used as key      axis.index = idx;      this._axesList.push(axis);      axesMap[axisType][idx] = axis;      axesCount[axisType]++;    };  }};/** * Update cartesian properties from series * @param  {module:echarts/model/Option} option * @private */gridProto._updateScale = function (ecModel, gridModel) {  // Reset scale  each(this._axesList, function (axis) {    axis.scale.setExtent(Infinity, -Infinity);  });  ecModel.eachSeries(function (seriesModel) {    if (isCartesian2D(seriesModel)) {      var axesModels = findAxesModels(seriesModel, ecModel);      var xAxisModel = axesModels[0];      var yAxisModel = axesModels[1];      if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)) {        return;      }      var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);      var data = seriesModel.getData();      var xAxis = cartesian.getAxis('x');      var yAxis = cartesian.getAxis('y');      if (data.type === 'list') {        unionExtent(data, xAxis, seriesModel);        unionExtent(data, yAxis, seriesModel);      }    }  }, this);  function unionExtent(data, axis, seriesModel) {    each(data.mapDimension(axis.dim, true), function (dim) {      axis.scale.unionExtentFromData( // For example, the extent of the orginal dimension      // is [0.1, 0.5], the extent of the `stackResultDimension`      // is [7, 9], the final extent should not include [0.1, 0.5].      data, getStackedDimension(data, dim));    });  }};/** * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined * @return {Object} {baseAxes: [], otherAxes: []} */gridProto.getTooltipAxes = function (dim) {  var baseAxes = [];  var otherAxes = [];  each(this.getCartesians(), function (cartesian) {    var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis();    var otherAxis = cartesian.getOtherAxis(baseAxis);    indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);    indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);  });  return {    baseAxes: baseAxes,    otherAxes: otherAxes  };};/** * @inner */function updateAxisTransform(axis, coordBase) {  var axisExtent = axis.getExtent();  var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform  axis.toGlobalCoord = axis.dim === 'x' ? function (coord) {    return coord + coordBase;  } : function (coord) {    return axisExtentSum - coord + coordBase;  };  axis.toLocalCoord = axis.dim === 'x' ? function (coord) {    return coord - coordBase;  } : function (coord) {    return axisExtentSum - coord + coordBase;  };}var axesTypes = ['xAxis', 'yAxis'];/** * @inner */function findAxesModels(seriesModel, ecModel) {  return map(axesTypes, function (axisType) {    var axisModel = seriesModel.getReferringComponents(axisType)[0];    return axisModel;  });}/** * @inner */function isCartesian2D(seriesModel) {  return seriesModel.get('coordinateSystem') === 'cartesian2d';}Grid.create = function (ecModel, api) {  var grids = [];  ecModel.eachComponent('grid', function (gridModel, idx) {    var grid = new Grid(gridModel, ecModel, api);    grid.name = 'grid_' + idx; // dataSampling requires axis extent, so resize    // should be performed in create stage.    grid.resize(gridModel, api, true);    gridModel.coordinateSystem = grid;    grids.push(grid);  }); // Inject the coordinateSystems into seriesModel  ecModel.eachSeries(function (seriesModel) {    if (!isCartesian2D(seriesModel)) {      return;    }    var axesModels = findAxesModels(seriesModel, ecModel);    var xAxisModel = axesModels[0];    var yAxisModel = axesModels[1];    var gridModel = xAxisModel.getCoordSysModel();    var grid = gridModel.coordinateSystem;    seriesModel.coordinateSystem = grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);  });  return grids;}; // For deciding which dimensions to use when creating list dataGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;CoordinateSystem.register('cartesian2d', Grid);var _default = Grid;module.exports = _default;
 |