diff --git a/src/coord/axisHelper.ts b/src/coord/axisHelper.ts index c487d52871..dd1350380d 100644 --- a/src/coord/axisHelper.ts +++ b/src/coord/axisHelper.ts @@ -292,14 +292,17 @@ export function getAxisRawValue(axis: Axis, tick: ScaleTick): number | string { /** * @param axis - * @return Be null/undefined if no labels. + * @return Return the largest, first and the last label BoundingRects. Be null/undefined if no labels. */ -export function estimateLabelUnionRect(axis: Axis) { +export function estimateLabelRect(axis: Axis) { const axisModel = axis.model; const scale = axis.scale; if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) { - return; + return { + labelUnionRect: null, + labelRects: [] + }; } let realNumberScaleTicks: ScaleTick[]; @@ -318,12 +321,10 @@ export function estimateLabelUnionRect(axis: Axis) { const axisLabelModel = axis.getLabelModel(); const labelFormatter = makeLabelFormatter(axis); - let rect; + let labelUnionRect; let step = 1; - // Simple optimization for large amount of labels - if (tickCount > 40) { - step = Math.ceil(tickCount / 40); - } + const labelRects = []; + for (let i = 0; i < tickCount; i += step) { const tick = realNumberScaleTicks ? realNumberScaleTicks[i] @@ -333,11 +334,11 @@ export function estimateLabelUnionRect(axis: Axis) { const label = labelFormatter(tick, i); const unrotatedSingleRect = axisLabelModel.getTextRect(label); const singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0); - - rect ? rect.union(singleRect) : (rect = singleRect); + labelRects.push(singleRect.clone()); + labelUnionRect ? labelUnionRect.union(singleRect) : (labelUnionRect = singleRect); } - return rect; + return {labelUnionRect, labelRects}; } function rotateTextRect(textRect: RectLike, rotate: number) { diff --git a/src/coord/cartesian/Grid.ts b/src/coord/cartesian/Grid.ts index 691effdd0e..5d876840e6 100644 --- a/src/coord/cartesian/Grid.ts +++ b/src/coord/cartesian/Grid.ts @@ -24,12 +24,12 @@ */ import {isObject, each, indexOf, retrieve3, keys} from 'zrender/src/core/util'; -import {getLayoutRect, LayoutRect} from '../../util/layout'; +import {box, getLayoutRect, LayoutRect} from '../../util/layout'; import { createScaleByModel, ifAxisCrossZero, niceScaleExtent, - estimateLabelUnionRect, + estimateLabelRect, getDataDimensionsOnAxis } from '../../coord/axisHelper'; import Cartesian2D, {cartesian2DDimensions} from './Cartesian2D'; @@ -53,6 +53,7 @@ import { isIntervalOrLogScale } from '../../scale/helper'; import { alignScaleTicks } from '../axisAlignTicks'; import IntervalScale from '../../scale/Interval'; import LogScale from '../../scale/Log'; +import BoundingRect from 'zrender/src/core/BoundingRect'; type Cartesian2DDimensionName = 'x' | 'y'; @@ -179,16 +180,14 @@ class Grid implements CoordinateSystemMaster { }); this._rect = gridRect; - const axesList = this._axesList; - adjustAxes(); // Minus label size if (isContainLabel) { each(axesList, function (axis) { if (!axis.model.get(['axisLabel', 'inside'])) { - const labelUnionRect = estimateLabelUnionRect(axis); + const {labelUnionRect} = estimateLabelRect(axis); if (labelUnionRect) { const dim: 'height' | 'width' = axis.isHorizontal() ? 'height' : 'width'; const margin = axis.model.get(['axisLabel', 'margin']); @@ -202,10 +201,37 @@ class Grid implements CoordinateSystemMaster { } } }); + adjustAxes(); + //Adjust grid.width to keep xAxis labels in dom + const xAxis = axesList[0].isHorizontal() ? axesList[0] : axesList[1]; + const {labelRects} = estimateLabelRect(xAxis); + //Find all displayed labels and create the union rect of them + const labelViews = xAxis.getViewLabels(); + let labelUnionRects: BoundingRect; + each(labelViews, function (label, index) { + //Only when axis type is 'category' or 'time' can 'tickValue' + //correctly point to the index of label. + //When axis type is 'value', tickValue is the exact value of that tick. + //In this case 'interval' would not work so 'index' is the correct index of label + const labelIdx = xAxis.type === 'category' ? label.tickValue : index; + const labelWidth = labelRects[labelIdx].width; + const labelX = xAxis.dataToCoord(label.tickValue) + gridRect.x - labelWidth / 2; + const labelrect = new BoundingRect(labelX, 0, labelWidth, 1); + labelUnionRects ? labelUnionRects.union(labelrect) : labelUnionRects = labelrect; + }); + const leftExceed = labelUnionRects.x; + const rightExceed = labelUnionRects.x + labelUnionRects.width - api.getWidth(); + //Check left margin + if (leftExceed < 0) { + gridRect.width -= -leftExceed; + gridRect.x += -leftExceed; + } + if (rightExceed > 0) { + gridRect.width -= rightExceed; + } adjustAxes(); } - each(this._coordsList, function (coord) { // Calculate affine matrix to accelerate the data to point transform. // If all the axes scales are time or value. diff --git a/test/gridContainLabel.html b/test/gridContainLabel.html new file mode 100644 index 0000000000..78fb3f8dd1 --- /dev/null +++ b/test/gridContainLabel.html @@ -0,0 +1,542 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +