| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- /*
- * 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.
- */
- /**
- * Grid is a region which contains at most 4 cartesian systems
- *
- * TODO Default cartesian
- */
- import { isObject, each, indexOf, retrieve3, keys, assert, eqNaN, find, retrieve2 } from 'zrender/lib/core/util.js';
- import { createBoxLayoutReference, getLayoutRect } from '../../util/layout.js';
- import { createScaleByModel, ifAxisCrossZero, niceScaleExtent, getDataDimensionsOnAxis, isNameLocationCenter, shouldAxisShow } from '../../coord/axisHelper.js';
- import Cartesian2D, { cartesian2DDimensions } from './Cartesian2D.js';
- import Axis2D from './Axis2D.js';
- import { SINGLE_REFERRING } from '../../util/model.js';
- // Depends on GridModel, AxisModel, which performs preprocess.
- import { OUTER_BOUNDS_CLAMP_DEFAULT, OUTER_BOUNDS_DEFAULT } from './GridModel.js';
- import { findAxisModels, createCartesianAxisViewCommonPartBuilder, updateCartesianAxisViewCommonPartBuilder, isCartesian2DInjectedAsDataCoordSys } from './cartesianAxisHelper.js';
- import { isIntervalOrLogScale } from '../../scale/helper.js';
- import { alignScaleTicks } from '../axisAlignTicks.js';
- import { expandOrShrinkRect, WH, XY } from '../../util/graphic.js';
- import { AxisBuilderSharedContext, resolveAxisNameOverlapDefault, moveIfOverlapByLinearLabels, getLabelInner } from '../../component/axis/AxisBuilder.js';
- import { error, log } from '../../util/log.js';
- import { AxisTickLabelComputingKind } from '../axisTickLabelBuilder.js';
- import { injectCoordSysByOption } from '../../core/CoordinateSystem.js';
- import { mathMax, parsePositionSizeOption } from '../../util/number.js';
- // margin is [top, right, bottom, left]
- var XY_TO_MARGIN_IDX = [[3, 1], [0, 2] // xyIdx 1 => 'y'
- ];
- var Grid = /** @class */function () {
- function Grid(gridModel, ecModel, api) {
- // FIXME:TS where used (different from registered type 'cartesian2d')?
- this.type = 'grid';
- this._coordsMap = {};
- this._coordsList = [];
- this._axesMap = {};
- this._axesList = [];
- this.axisPointerEnabled = true;
- this.dimensions = cartesian2DDimensions;
- this._initCartesian(gridModel, ecModel, api);
- this.model = gridModel;
- }
- Grid.prototype.getRect = function () {
- return this._rect;
- };
- Grid.prototype.update = function (ecModel, api) {
- var axesMap = this._axesMap;
- this._updateScale(ecModel, this.model);
- function updateAxisTicks(axes) {
- var alignTo;
- // Axis is added in order of axisIndex.
- var axesIndices = keys(axes);
- var len = axesIndices.length;
- if (!len) {
- return;
- }
- var axisNeedsAlign = [];
- // Process once and calculate the ticks for those don't use alignTicks.
- for (var i = len - 1; i >= 0; i--) {
- var idx = +axesIndices[i]; // Convert to number.
- var axis = axes[idx];
- var model = axis.model;
- var scale = axis.scale;
- if (
- // Only value and log axis without interval support alignTicks.
- isIntervalOrLogScale(scale) && model.get('alignTicks') && model.get('interval') == null) {
- axisNeedsAlign.push(axis);
- } else {
- niceScaleExtent(scale, model);
- if (isIntervalOrLogScale(scale)) {
- // Can only align to interval or log axis.
- alignTo = axis;
- }
- }
- }
- ;
- // All axes has set alignTicks. Pick the first one.
- // PENDING. Should we find the axis that both set interval, min, max and align to this one?
- if (axisNeedsAlign.length) {
- if (!alignTo) {
- alignTo = axisNeedsAlign.pop();
- niceScaleExtent(alignTo.scale, alignTo.model);
- }
- each(axisNeedsAlign, function (axis) {
- alignScaleTicks(axis.scale, axis.model, alignTo.scale);
- });
- }
- }
- updateAxisTicks(axesMap.x);
- updateAxisTicks(axesMap.y);
- // 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);
- };
- /**
- * Resize the grid.
- *
- * [NOTE]
- * If both "grid.containLabel/grid.contain" and pixel-required-data-processing (such as, "dataSampling")
- * exist, circular dependency occurs in logic.
- * The final compromised sequence is:
- * 1. Calculate "axis.extent" (pixel extent) and AffineTransform based on only "grid layout options".
- * Not accurate if "grid.containLabel/grid.contain" is required, but it is a compromise to avoid
- * circular dependency.
- * 2. Perform "series data processing" (where "dataSampling" requires "axis.extent").
- * 3. Calculate "scale.extent" (data extent) based on "processed series data".
- * 4. Modify "axis.extent" for "grid.containLabel/grid.contain":
- * 4.1. Calculate "axis labels" based on "scale.extent".
- * 4.2. Modify "axis.extent" by the bounding rects of "axis labels and names".
- */
- Grid.prototype.resize = function (gridModel, api, beforeDataProcessing) {
- var layoutRef = createBoxLayoutReference(gridModel, api);
- var gridRect = this._rect = getLayoutRect(gridModel.getBoxLayoutParams(), layoutRef.refContainer);
- // PENDING: whether to support that if the input `coord` is out of the base coord sys,
- // do not render anything. At present, the behavior is undefined.
- var axesMap = this._axesMap;
- var coordsList = this._coordsList;
- var optionContainLabel = gridModel.get('containLabel'); // No `.get(, true)` for backward compat.
- updateAllAxisExtentTransByGridRect(axesMap, gridRect);
- if (!beforeDataProcessing) {
- var axisBuilderSharedCtx = createAxisBiulders(gridRect, coordsList, axesMap, optionContainLabel, api);
- var noPxChange = void 0;
- if (optionContainLabel) {
- if (legacyLayOutGridByContainLabel) {
- // console.time('legacyLayOutGridByContainLabel');
- legacyLayOutGridByContainLabel(this._axesList, gridRect);
- updateAllAxisExtentTransByGridRect(axesMap, gridRect);
- // console.timeEnd('legacyLayOutGridByContainLabel');
- } else {
- if (process.env.NODE_ENV !== 'production') {
- log('Specified `grid.containLabel` but no `use(LegacyGridContainLabel)`;' + 'use `grid.outerBounds` instead.', true);
- }
- noPxChange = layOutGridByOuterBounds(gridRect.clone(), 'axisLabel', null, gridRect, axesMap, axisBuilderSharedCtx, layoutRef);
- }
- } else {
- var _a = prepareOuterBounds(gridModel, gridRect, layoutRef),
- outerBoundsRect = _a.outerBoundsRect,
- parsedOuterBoundsContain = _a.parsedOuterBoundsContain,
- outerBoundsClamp = _a.outerBoundsClamp;
- if (outerBoundsRect) {
- // console.time('layOutGridByOuterBounds');
- noPxChange = layOutGridByOuterBounds(outerBoundsRect, parsedOuterBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef);
- // console.timeEnd('layOutGridByOuterBounds');
- }
- }
- // console.time('buildAxesView_determine');
- createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.determine, null, noPxChange, layoutRef);
- // console.timeEnd('buildAxesView_determine');
- } // End of beforeDataProcessing
- each(this._coordsList, function (coord) {
- // Calculate affine matrix to accelerate the data to point transform.
- // If all the axes scales are time or value.
- coord.calcAffineTransform();
- });
- };
- Grid.prototype.getAxis = function (dim, axisIndex) {
- var axesMapOnDim = this._axesMap[dim];
- if (axesMapOnDim != null) {
- return axesMapOnDim[axisIndex || 0];
- }
- };
- Grid.prototype.getAxes = function () {
- return this._axesList.slice();
- };
- Grid.prototype.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;
- }
- 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];
- }
- }
- };
- Grid.prototype.getCartesians = function () {
- return this._coordsList.slice();
- };
- /**
- * @implements
- */
- Grid.prototype.convertToPixel = function (ecModel, finder, value) {
- var target = this._findConvertTarget(finder);
- return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;
- };
- /**
- * @implements
- */
- Grid.prototype.convertFromPixel = function (ecModel, finder, value) {
- var target = this._findConvertTarget(finder);
- return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;
- };
- Grid.prototype._findConvertTarget = function (finder) {
- var seriesModel = finder.seriesModel;
- var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
- var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[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
- */
- Grid.prototype.containPoint = function (point) {
- var coord = this._coordsList[0];
- if (coord) {
- return coord.containPoint(point);
- }
- };
- /**
- * Initialize cartesian coordinate systems
- */
- Grid.prototype._initCartesian = function (gridModel, ecModel, api) {
- var _this = this;
- var grid = this;
- 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.master = _this;
- cartesian.model = gridModel;
- _this._coordsMap[key] = cartesian;
- _this._coordsList.push(cartesian);
- cartesian.addAxis(xAxis);
- cartesian.addAxis(yAxis);
- });
- });
- function createAxisCreator(dimName) {
- return function (axisModel, idx) {
- if (!isAxisUsedInTheGrid(axisModel, gridModel)) {
- return;
- }
- var axisPosition = axisModel.get('position');
- if (dimName === '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(dimName, 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 = grid;
- // Index of axis, can be used as key
- axis.index = idx;
- grid._axesList.push(axis);
- axesMap[dimName][idx] = axis;
- axesCount[dimName]++;
- };
- }
- };
- /**
- * Update cartesian properties from series.
- */
- Grid.prototype._updateScale = function (ecModel, gridModel) {
- // Reset scale
- each(this._axesList, function (axis) {
- axis.scale.setExtent(Infinity, -Infinity);
- if (axis.type === 'category') {
- var categorySortInfo = axis.model.get('categorySortInfo');
- axis.scale.setSortInfo(categorySortInfo);
- }
- });
- ecModel.eachSeries(function (seriesModel) {
- // If pie (or other similar series) use cartesian2d, the unionExtent logic below is
- // wrong, therefore skip it temporarily. See also in `defaultAxisExtentFromData.ts`.
- // TODO: support union extent in this case.
- if (isCartesian2DInjectedAsDataCoordSys(seriesModel)) {
- var axesModelMap = findAxisModels(seriesModel);
- var xAxisModel = axesModelMap.xAxisModel;
- var yAxisModel = axesModelMap.yAxisModel;
- if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) {
- return;
- }
- var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
- var data = seriesModel.getData();
- var xAxis = cartesian.getAxis('x');
- var yAxis = cartesian.getAxis('y');
- unionExtent(data, xAxis);
- unionExtent(data, yAxis);
- }
- }, this);
- function unionExtent(data, axis) {
- each(getDataDimensionsOnAxis(data, axis.dim), function (dim) {
- axis.scale.unionExtentFromData(data, dim);
- });
- }
- };
- /**
- * @param dim 'x' or 'y' or 'auto' or null/undefined
- */
- Grid.prototype.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
- };
- };
- 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) {
- injectCoordSysByOption({
- targetModel: seriesModel,
- coordSysType: 'cartesian2d',
- coordSysProvider: coordSysProvider
- });
- function coordSysProvider() {
- var axesModelMap = findAxisModels(seriesModel);
- var xAxisModel = axesModelMap.xAxisModel;
- var yAxisModel = axesModelMap.yAxisModel;
- var gridModel = xAxisModel.getCoordSysModel();
- if (process.env.NODE_ENV !== 'production') {
- if (!gridModel) {
- throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found');
- }
- if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {
- throw new Error('xAxis and yAxis must use the same grid');
- }
- }
- var grid = gridModel.coordinateSystem;
- return grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
- }
- });
- return grids;
- };
- // For deciding which dimensions to use when creating list data
- Grid.dimensions = cartesian2DDimensions;
- return Grid;
- }();
- /**
- * Check if the axis is used in the specified grid.
- */
- function isAxisUsedInTheGrid(axisModel, gridModel) {
- return axisModel.getCoordSysModel() === gridModel;
- }
- function fixAxisOnZero(axesMap, otherAxisDim, axis,
- // Key: see `getOnZeroRecordKey`
- 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);
- }
- 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;
- };
- }
- function updateAllAxisExtentTransByGridRect(axesMap, gridRect) {
- each(axesMap.x, function (axis) {
- return updateAxisExtentTransByGridRect(axis, gridRect.x, gridRect.width);
- });
- each(axesMap.y, function (axis) {
- return updateAxisExtentTransByGridRect(axis, gridRect.y, gridRect.height);
- });
- }
- function updateAxisExtentTransByGridRect(axis, gridXY, gridWH) {
- var extent = [0, gridWH];
- var idx = axis.inverse ? 1 : 0;
- axis.setExtent(extent[idx], extent[1 - idx]);
- updateAxisTransform(axis, gridXY);
- }
- var legacyLayOutGridByContainLabel;
- export function registerLegacyGridContainLabelImpl(impl) {
- legacyLayOutGridByContainLabel = impl;
- }
- // Return noPxChange.
- function layOutGridByOuterBounds(outerBoundsRect, outerBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef) {
- if (process.env.NODE_ENV !== 'production') {
- assert(outerBoundsContain === 'all' || outerBoundsContain === 'axisLabel');
- }
- // Assume `updateAllAxisExtentTransByGridRect` has been performed once before this call.
- // [NOTE]:
- // - The bounding rect of the axis elements might be sensitve to variations in `axis.extent` due to strategies
- // like hideOverlap/moveOverlap. @see the comment in `LabelLayoutBase['suggestIgnore']`.
- // - The final `gridRect` might be slightly smaller than the ideally expected result if labels are giant and
- // get hidden due to overlapping. More iterations could improve precision, but not performant. We consider
- // the current result acceptable, since no alignment among charts can be guaranteed when using this feature.
- createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.estimate, outerBoundsContain, false, layoutRef);
- var margin = [0, 0, 0, 0];
- fillLabelNameOverflowOnOneDimension(0);
- fillLabelNameOverflowOnOneDimension(1);
- // If axis is blank, no label can be used to detect overflow.
- // gridRect itself should not overflow.
- fillMarginOnOneDimension(gridRect, 0, NaN);
- fillMarginOnOneDimension(gridRect, 1, NaN);
- var noPxChange = find(margin, function (item) {
- return item > 0;
- }) == null;
- expandOrShrinkRect(gridRect, margin, true, true, outerBoundsClamp);
- updateAllAxisExtentTransByGridRect(axesMap, gridRect);
- return noPxChange;
- function fillLabelNameOverflowOnOneDimension(xyIdx) {
- each(axesMap[XY[xyIdx]], function (axis) {
- if (!shouldAxisShow(axis.model)) {
- return;
- }
- // FIXME: zr Group.union may wrongly union (0, 0, 0, 0) and not performant.
- // unionRect.union(axis.axisBuilder.group.getBoundingRect());
- // If ussing Group.getBoundingRect to calculate shrink space, it is not strictly accurate when
- // the outermost label is ignored and the secondary label is very long and contribute to the
- // union extension:
- // -|---|---|---|
- // 1,000,000,000
- // Therefore we calculate them one by one.
- // Also considered axis may be blank or no labels.
- var sharedRecord = axisBuilderSharedCtx.ensureRecord(axis.model);
- var labelInfoList = sharedRecord.labelInfoList;
- if (labelInfoList) {
- for (var idx = 0; idx < labelInfoList.length; idx++) {
- var labelInfo = labelInfoList[idx];
- var proportion = axis.scale.normalize(getLabelInner(labelInfo.label).tickValue);
- proportion = xyIdx === 1 ? 1 - proportion : proportion;
- // xAxis use proportion on x, yAxis use proprotion on y, otherwise not.
- fillMarginOnOneDimension(labelInfo.rect, xyIdx, proportion);
- fillMarginOnOneDimension(labelInfo.rect, 1 - xyIdx, NaN);
- }
- }
- var nameLayout = sharedRecord.nameLayout;
- if (nameLayout) {
- var proportion = isNameLocationCenter(sharedRecord.nameLocation) ? 0.5 : NaN;
- fillMarginOnOneDimension(nameLayout.rect, xyIdx, proportion);
- fillMarginOnOneDimension(nameLayout.rect, 1 - xyIdx, NaN);
- }
- });
- }
- function fillMarginOnOneDimension(itemRect, xyIdx, proportion // NaN mean no use proportion
- ) {
- var overflow1 = outerBoundsRect[XY[xyIdx]] - itemRect[XY[xyIdx]];
- var overflow2 = itemRect[WH[xyIdx]] + itemRect[XY[xyIdx]] - (outerBoundsRect[WH[xyIdx]] + outerBoundsRect[XY[xyIdx]]);
- overflow1 = applyProportion(overflow1, 1 - proportion);
- overflow2 = applyProportion(overflow2, proportion);
- var minIdx = XY_TO_MARGIN_IDX[xyIdx][0];
- var maxIdx = XY_TO_MARGIN_IDX[xyIdx][1];
- margin[minIdx] = mathMax(margin[minIdx], overflow1);
- margin[maxIdx] = mathMax(margin[maxIdx], overflow2);
- }
- function applyProportion(overflow, proportion) {
- // proportion is not likely to near zero. If so, give up shrink
- if (overflow > 0 && !eqNaN(proportion) && proportion > 1e-4) {
- overflow /= proportion;
- }
- return overflow;
- }
- }
- function createAxisBiulders(gridRect, cartesians, axesMap, optionContainLabel, api) {
- var axisBuilderSharedCtx = new AxisBuilderSharedContext(resolveAxisNameOverlapForGrid);
- each(axesMap, function (axisList) {
- return each(axisList, function (axis) {
- if (shouldAxisShow(axis.model)) {
- // See `AxisBaseOptionCommon['nameMoveOverlap']`.
- var defaultNameMoveOverlap = !optionContainLabel;
- axis.axisBuilder = createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axis.model, api, axisBuilderSharedCtx, defaultNameMoveOverlap);
- }
- });
- });
- return axisBuilderSharedCtx;
- }
- /**
- * Promote the axis-elements-building from "view render" stage to "coordinate system resize" stage.
- * This is aimed to resovle overlap across multiple axes, since currently it's hard to reconcile
- * multiple axes in "view render" stage.
- *
- * [CAUTION] But this promotion assumes that the subsequent "visual mapping" stage does not affect
- * this axis-elements-building; otherwise we have to refactor it again.
- */
- function createOrUpdateAxesView(gridRect, axesMap, kind, outerBoundsContain, noPxChange, layoutRef) {
- var isDetermine = kind === AxisTickLabelComputingKind.determine;
- each(axesMap, function (axisList) {
- return each(axisList, function (axis) {
- if (shouldAxisShow(axis.model)) {
- updateCartesianAxisViewCommonPartBuilder(axis.axisBuilder, gridRect, axis.model);
- axis.axisBuilder.build(isDetermine ? {
- axisTickLabelDetermine: true
- } : {
- axisTickLabelEstimate: true
- }, {
- noPxChange: noPxChange
- });
- }
- });
- });
- var nameMarginLevelMap = {
- x: 0,
- y: 0
- };
- calcNameMarginLevel(0);
- calcNameMarginLevel(1);
- function calcNameMarginLevel(xyIdx) {
- nameMarginLevelMap[XY[1 - xyIdx]] = gridRect[WH[xyIdx]] <= layoutRef.refContainer[WH[xyIdx]] * 0.5 ? 0 : 1 - xyIdx === 1 ? 2 : 1;
- }
- each(axesMap, function (axisList, xy) {
- return each(axisList, function (axis) {
- if (shouldAxisShow(axis.model)) {
- if (outerBoundsContain === 'all' || isDetermine) {
- // To resolve overlap, `axisName` layout depends on `axisTickLabel` layout result
- // (all of the axes of the same `grid`; consider multiple x or y axes).
- axis.axisBuilder.build({
- axisName: true
- }, {
- nameMarginLevel: nameMarginLevelMap[xy]
- });
- }
- if (isDetermine) {
- axis.axisBuilder.build({
- axisLine: true
- });
- }
- }
- });
- });
- }
- function prepareOuterBounds(gridModel, rawRridRect, layoutRef) {
- var outerBoundsRect;
- var optionOuterBoundsMode = gridModel.get('outerBoundsMode', true);
- if (optionOuterBoundsMode === 'same') {
- outerBoundsRect = rawRridRect.clone();
- } else if (optionOuterBoundsMode == null || optionOuterBoundsMode === 'auto') {
- outerBoundsRect = getLayoutRect(gridModel.get('outerBounds', true) || OUTER_BOUNDS_DEFAULT, layoutRef.refContainer);
- } else if (optionOuterBoundsMode !== 'none') {
- if (process.env.NODE_ENV !== 'production') {
- error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsMode.");
- }
- }
- var optionOuterBoundsContain = gridModel.get('outerBoundsContain', true);
- var parsedOuterBoundsContain;
- if (optionOuterBoundsContain == null || optionOuterBoundsContain === 'auto') {
- parsedOuterBoundsContain = 'all';
- } else if (indexOf(['all', 'axisLabel'], optionOuterBoundsContain) < 0) {
- if (process.env.NODE_ENV !== 'production') {
- error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsContain.");
- }
- parsedOuterBoundsContain = 'all';
- } else {
- parsedOuterBoundsContain = optionOuterBoundsContain;
- }
- var outerBoundsClamp = [parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampWidth', true), OUTER_BOUNDS_CLAMP_DEFAULT[0]), rawRridRect.width), parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampHeight', true), OUTER_BOUNDS_CLAMP_DEFAULT[1]), rawRridRect.height)];
- return {
- outerBoundsRect: outerBoundsRect,
- parsedOuterBoundsContain: parsedOuterBoundsContain,
- outerBoundsClamp: outerBoundsClamp
- };
- }
- var resolveAxisNameOverlapForGrid = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) {
- var perpendicularDim = axisModel.axis.dim === 'x' ? 'y' : 'x';
- resolveAxisNameOverlapDefault(cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord);
- // If nameLocation 'center', and there are multiple axes parallel to this axis, do not adjust by
- // other axes, because the axis name should be close to its axis line as much as possible even
- // if overlapping; otherwise it might cause misleading.
- // If nameLocation 'center', do not adjust by perpendicular axes, since they are not likely to overlap.
- // If nameLocation 'start'/'end', move name within the same direction to escape overlap with the
- // perpendicular axes.
- if (!isNameLocationCenter(cfg.nameLocation)) {
- each(ctx.recordMap[perpendicularDim], function (perpenRecord) {
- // perpendicular axis may be no name.
- if (perpenRecord && perpenRecord.labelInfoList && perpenRecord.dirVec) {
- moveIfOverlapByLinearLabels(perpenRecord.labelInfoList, perpenRecord.dirVec, nameLayoutInfo, nameMoveDirVec);
- }
- });
- }
- };
- export default Grid;
|