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 data
- Grid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;
- CoordinateSystem.register('cartesian2d', Grid);
- var _default = Grid;
- module.exports = _default;
|