diff --git a/__tests__/integration/snapshots/static/stocksLineLabelExceedAdjust.svg b/__tests__/integration/snapshots/static/stocksLineLabelExceedAdjust.svg
new file mode 100644
index 0000000000..7bf4418920
--- /dev/null
+++ b/__tests__/integration/snapshots/static/stocksLineLabelExceedAdjust.svg
@@ -0,0 +1,3622 @@
+
\ No newline at end of file
diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts
index 542b150131..5e910a719e 100644
--- a/__tests__/plots/static/index.ts
+++ b/__tests__/plots/static/index.ts
@@ -253,6 +253,7 @@ export { alphabetIntervalViewStyle } from './alphabet-interval-view-style';
export { vennBasic } from './venn-basic';
export { vennHollow } from './venn-hollow';
export { stocksLineVarSize } from './stocks-line-var-size';
+export { stocksLineLabelExceedAdjust } from './stocks-line-label-exceed-adjust';
export { barleyLineTrail } from './barley-line-trail';
export { mockAxisX } from './mock-axisX';
export { mockAxisY } from './mock-axisY';
diff --git a/__tests__/plots/static/stocks-line-label-exceed-adjust.ts b/__tests__/plots/static/stocks-line-label-exceed-adjust.ts
new file mode 100644
index 0000000000..e95328340b
--- /dev/null
+++ b/__tests__/plots/static/stocks-line-label-exceed-adjust.ts
@@ -0,0 +1,26 @@
+import { G2Spec } from '../../../src';
+
+export function stocksLineLabelExceedAdjust(): G2Spec {
+ return {
+ type: 'line',
+ data: {
+ type: 'fetch',
+ value: 'data/stocks.csv',
+ },
+ transform: [{ type: 'groupX', y: 'mean' }],
+ encode: {
+ x: (d) => new Date(d.date).getFullYear(),
+ y: 'price',
+ color: 'symbol',
+ },
+ labels: [
+ {
+ text: 'price',
+ transform: [{ type: 'exceedAdjust' }],
+ style: {
+ fontSize: 10,
+ },
+ },
+ ],
+ };
+}
diff --git a/__tests__/unit/lib/core.spec.ts b/__tests__/unit/lib/core.spec.ts
index 712af576bc..225cba8c6c 100644
--- a/__tests__/unit/lib/core.spec.ts
+++ b/__tests__/unit/lib/core.spec.ts
@@ -162,6 +162,7 @@ import {
ContrastReverse,
OverlapHide,
OverlapDodgeY,
+ ExceedAdjust,
} from '../../../src/label-transform';
describe('corelib', () => {
@@ -315,6 +316,7 @@ describe('corelib', () => {
'composition.repeatMatrix': RepeatMatrix,
'composition.facetCircle': FacetCircle,
'composition.timingKeyframe': TimingKeyframe,
+ 'labelTransform.exceedAdjust': ExceedAdjust,
'labelTransform.overlapHide': OverlapHide,
'labelTransform.overlapDodgeY': OverlapDodgeY,
'labelTransform.overflowHide': OverflowHide,
diff --git a/__tests__/unit/lib/std.spec.ts b/__tests__/unit/lib/std.spec.ts
index b4b92a6529..9ded77f4f7 100644
--- a/__tests__/unit/lib/std.spec.ts
+++ b/__tests__/unit/lib/std.spec.ts
@@ -176,6 +176,7 @@ import {
ContrastReverse,
OverlapHide,
OverlapDodgeY,
+ ExceedAdjust,
} from '../../../src/label-transform';
describe('stdlib', () => {
@@ -343,6 +344,7 @@ describe('stdlib', () => {
'composition.timingKeyframe': TimingKeyframe,
'labelTransform.overlapHide': OverlapHide,
'labelTransform.overlapDodgeY': OverlapDodgeY,
+ 'labelTransform.exceedAdjust': ExceedAdjust,
'labelTransform.overflowHide': OverflowHide,
'labelTransform.contrastReverse': ContrastReverse,
'composition.geoView': GeoView,
diff --git a/site/docs/spec/label/exceedAdjust.en.md b/site/docs/spec/label/exceedAdjust.en.md
new file mode 100644
index 0000000000..f0c36c3458
--- /dev/null
+++ b/site/docs/spec/label/exceedAdjust.en.md
@@ -0,0 +1,6 @@
+---
+title: exceedAdjust
+order: 1
+---
+
+
diff --git a/site/docs/spec/label/exceedAdjust.zh.md b/site/docs/spec/label/exceedAdjust.zh.md
new file mode 100644
index 0000000000..bcdd024154
--- /dev/null
+++ b/site/docs/spec/label/exceedAdjust.zh.md
@@ -0,0 +1,31 @@
+---
+title: exceedAdjust
+order: 1
+---
+
+`exceedAdjust` 会自动对标签做溢出检测和矫正,即当标签超出视图区域时,会对标签自动做反方向的位移。
+
+## 开始使用
+
+
+
+```ts
+chart
+ .line()
+ .encode('x', 'letter')
+ .encode('y', 'frequency')
+ .encode('color', 'type')
+ /* ... */
+ .label({
+ text: 'frequency',
+ transform: [
+ {
+ type: 'exceedAdjust',
+ },
+ ],
+ });
+```
+
+## 选项
+
+* 暂无
diff --git a/src/label-transform/exceedAdjust.ts b/src/label-transform/exceedAdjust.ts
new file mode 100644
index 0000000000..a169a7daac
--- /dev/null
+++ b/src/label-transform/exceedAdjust.ts
@@ -0,0 +1,61 @@
+import { DisplayObject } from '@antv/g';
+import { LabelTransformComponent as LLC } from '../runtime';
+import { ExceedAdjustLabel } from '../spec';
+import { Bounds } from '../utils/bounds';
+import { show } from '../utils/style';
+
+const adjustPosition = (target: Bounds, edge: Bounds) => {
+ const [[minEdgeX, minEdgeY], [maxEdgeX, maxEdgeY]] = edge;
+ const [[minX, minY], [maxX, maxY]] = target;
+
+ let changeX = 0,
+ changeY = 0;
+
+ // x-axis
+ if (minX < minEdgeX) {
+ changeX = minEdgeX - minX;
+ } else if (maxX > maxEdgeX) {
+ changeX = maxEdgeX - maxX;
+ }
+
+ // y-axis
+ if (minY < minEdgeY) {
+ changeY = minEdgeY - minY;
+ } else if (maxY > maxEdgeY) {
+ changeY = maxEdgeY - maxY;
+ }
+
+ return [changeX, changeY];
+};
+
+export type ExceedAdjustOptions = Omit;
+
+/**
+ * adjust the label when exceed the plot
+ */
+export const ExceedAdjust: LLC = () => {
+ return (labels: DisplayObject[], { canvas }) => {
+ const { width, height } = canvas.getConfig();
+
+ labels.forEach((l) => {
+ show(l);
+ const { max, min } = l.getRenderBounds();
+ const [xMax, yMax] = max,
+ [xMin, yMin] = min;
+ const changeValue = adjustPosition(
+ [
+ [xMin, yMin],
+ [xMax, yMax],
+ ],
+ [
+ [0, 0],
+ [width, height],
+ ],
+ );
+ l.style.x += changeValue[0];
+ l.style.y += changeValue[1];
+ });
+
+ return labels;
+ };
+};
diff --git a/src/label-transform/index.ts b/src/label-transform/index.ts
index 42c6d3bf57..a3c9ce1a47 100644
--- a/src/label-transform/index.ts
+++ b/src/label-transform/index.ts
@@ -2,8 +2,10 @@ export { OverlapHide } from './overlapHide';
export { OverlapDodgeY } from './overlapDodgeY';
export { ContrastReverse } from './contrastReverse';
export { OverflowHide } from './overflowHide';
+export { ExceedAdjust } from './exceedAdjust';
export type { OverlapHideOptions } from './overlapHide';
export type { OverlapDodgeYOptions } from './overlapDodgeY';
export type { ContrastReverseOptions } from './contrastReverse';
export type { OverflowHideOptions } from './overflowHide';
+export type { ExceedAdjustOptions } from './exceedAdjust';
diff --git a/src/lib/core.ts b/src/lib/core.ts
index 7a9fc8f9a4..c1f01003c0 100644
--- a/src/lib/core.ts
+++ b/src/lib/core.ts
@@ -161,6 +161,7 @@ import {
OverflowHide,
ContrastReverse,
OverlapHide,
+ ExceedAdjust,
} from '../label-transform';
export function corelib() {
@@ -317,5 +318,6 @@ export function corelib() {
'labelTransform.overlapDodgeY': OverlapDodgeY,
'labelTransform.overflowHide': OverflowHide,
'labelTransform.contrastReverse': ContrastReverse,
+ 'labelTransform.exceedAdjust': ExceedAdjust,
} as const;
}
diff --git a/src/spec/labelTransform.ts b/src/spec/labelTransform.ts
index c97a022d1b..c0926663a4 100644
--- a/src/spec/labelTransform.ts
+++ b/src/spec/labelTransform.ts
@@ -37,3 +37,7 @@ export type ContrastReverseLabelTransform = {
export type OverflowHideLabelTransform = {
type: 'overflowHide';
};
+
+export type ExceedAdjustLabel = {
+ type: 'exceedAdjust';
+};