/* * 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;