diff --git a/package.json b/package.json index 611f3f5bca..0f11e13def 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g2", - "version": "4.1.0-beta.17", + "version": "4.1.0-beta.18", "description": "the Grammar of Graphics in Javascript", "main": "lib/index.js", "module": "esm/index.js", diff --git a/src/chart/layout/padding-cal.ts b/src/chart/layout/padding-cal.ts index 6a59bbb541..7a71d1a827 100644 --- a/src/chart/layout/padding-cal.ts +++ b/src/chart/layout/padding-cal.ts @@ -2,6 +2,10 @@ import { DIRECTION } from '../../constant'; import { BBox } from '../../dependents'; import { Padding } from '../../interface'; +export type PaddingCalCtor = { + readonly instance: (top?: number, right?: number, bottom?: number, left?: number) => PaddingCal; +}; + /** @ignore */ export class PaddingCal { private top: number; @@ -9,6 +13,17 @@ export class PaddingCal { private bottom: number; private left: number; + /** + * 使用静态方法创建一个 + * @param top + * @param right + * @param bottom + * @param left + */ + public static instance(top: number = 0, right: number = 0, bottom: number = 0, left: number = 0) { + return new PaddingCal(top, right, bottom, left); + } + /** * 初始的 padding 数据 * @param top @@ -98,4 +113,11 @@ export class PaddingCal { public getPadding(): Padding { return [this.top, this.right, this.bottom, this.left]; } + + /** + * clone 一个 padding cal + */ + public clone(): PaddingCal { + return new PaddingCal(...this.getPadding()); + } } diff --git a/src/chart/util/sync-view-padding.ts b/src/chart/util/sync-view-padding.ts new file mode 100644 index 0000000000..92a1e8d6db --- /dev/null +++ b/src/chart/util/sync-view-padding.ts @@ -0,0 +1,17 @@ +import { PaddingCalCtor } from '../layout/padding-cal'; +import{ View } from '../view'; + +/** + * 默认的 syncViewPadding 逻辑 + * @param chart + * @param views + * @param PC: PaddingCalCtor + */ +export function defaultSyncViewPadding(chart: View, views: View[], PC: PaddingCalCtor) { + const syncPadding = PC.instance(); + + // 所有的 view 的 autoPadding 指向同一个引用 + views.forEach((v: View) => { + v.autoPadding = syncPadding.max(v.autoPadding.getPadding()); + }); +} diff --git a/src/chart/view.ts b/src/chart/view.ts index 1b76ff6604..7056e18ce4 100644 --- a/src/chart/view.ts +++ b/src/chart/view.ts @@ -63,6 +63,7 @@ import defaultLayout, { Layout } from './layout'; import { ScalePool } from './util/scale-pool'; import { PaddingCal } from './layout/padding-cal'; import { calculatePadding } from './layout/auto'; +import { defaultSyncViewPadding } from './util/sync-view-padding'; /** * G2 视图 View 类 @@ -1348,15 +1349,13 @@ export class View extends Base { */ protected renderLayoutRecursive(isUpdate: boolean) { // 1. 同步子 view padding - if (this.syncViewPadding) { - const syncPadding = new PaddingCal(); + // 根据配置获取 padding + const syncViewPaddingFn = this.syncViewPadding === true ? defaultSyncViewPadding : + isFunction(this.syncViewPadding) ? this.syncViewPadding : undefined; - // 所有的 view 的 autoPadding 指向同一个引用 - this.views.forEach((v: View) => { - v.autoPadding = syncPadding.max(v.autoPadding.getPadding()); - }); - - // 更新 coordinate + if (syncViewPaddingFn) { + syncViewPaddingFn(this, this.views, PaddingCal); + // 同步 padding 之后,更新 coordinate this.views.forEach((v: View) => { v.coordinateBBox = v.viewBBox.shrink(v.autoPadding.getPadding()); v.adjustCoordinate(); diff --git a/src/core.ts b/src/core.ts index 05d27abd0c..962b5f56c0 100644 --- a/src/core.ts +++ b/src/core.ts @@ -1,6 +1,6 @@ /* G2 的一个壳子,不包含 Geometry,由开发者自己定义和引入 */ -export const VERSION = '4.1.0-beta.17'; +export const VERSION = '4.1.0-beta.18'; // 核心基类导出 export { Chart, View, Event } from './chart'; // Chart, View 类 diff --git a/src/interface.ts b/src/interface.ts index 7019b07495..e16f8303bc 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -36,6 +36,7 @@ import { import { View } from './chart'; import { Facet } from './facet'; import Element from './geometry/element'; +import { PaddingCalCtor } from './chart/layout/padding-cal'; // ============================ 基础类型 ============================ /** 通用对象 */ @@ -797,6 +798,8 @@ export interface ChartCfg readonly defaultInteractions?: string[]; } +export type SyncViewPaddingFn = (chart: View, views: View[], PC: PaddingCalCtor) => void; + /** View 构造参数 */ export interface ViewCfg { /** View id,可以由外部传入 */ @@ -833,13 +836,15 @@ export interface ViewCfg { */ readonly appendPadding?: ViewAppendPadding; /** - * 是否同步子 view 的 padding + * 是否同步子 view 的 padding,可以是 boolean / SyncViewPaddingFn * 比如: * view1 的 padding 10 * view2 的 padding 20 - * 那么两个子 view 的 padding 统一变成最大的 20(后面可以传入 function 自己写策略) + * 那么两个子 view 的 padding 统一变成最大的 20. + * + * 如果是 Funcion,则使用自定义的方式去计算子 view 的 padding,这个函数中去修改所有的 views autoPadding 值 */ - readonly syncViewPadding?: boolean; + readonly syncViewPadding?: boolean | SyncViewPaddingFn; /** 设置 view 实例主题。 */ readonly theme?: LooseObject | string; /** diff --git a/tests/bugs/2849-spec.ts b/tests/bugs/2849-spec.ts index b418ee34ef..33731c84cd 100644 --- a/tests/bugs/2849-spec.ts +++ b/tests/bugs/2849-spec.ts @@ -1,8 +1,9 @@ import { Chart } from '../../src'; +import { PaddingCal, PaddingCalCtor } from '../../src/chart/layout/padding-cal'; import { createDiv } from '../util/dom'; describe('2849', () => { - it('2849', () => { + it('boolean', () => { const chart = new Chart({ container: createDiv(), autoFit: false, @@ -37,5 +38,49 @@ describe('2849', () => { // 不会创建多份 controller expect(chart.views[0].controllers.length).toBe(6); + }); + + it('function', () => { + // 均分画布 + const fn = jest.fn((c, views, PC: PaddingCalCtor) => { + const [v1, v2] = views; + v1.autoPadding = PC.instance(40, 200, 40, 40); + v2.autoPadding = PC.instance(40, 40, 40, 200); + }); + + const chart = new Chart({ + container: createDiv(), + autoFit: false, + width: 400, + height: 400, + syncViewPadding: fn, + options: { + views: [ + { + options: { + data: [{ x: 'A', y: 10 }, { x: 'B', y: 15 }, { x: 'C', 'y': 40 }], + scales: { y: { nice: true } }, + geometries: [ + { type: 'interval', position: { fields: ['x', 'y'] } } + ] + } + }, + { + options: { + data: [{ x: 'A', y1: 23 }, { x: 'B', y1: 40 }, { x: 'C', y1: 100 }], + geometries: [ + { type: 'line', position: { fields: ['x', 'y1'] }, size: { values: [2] } } + ], + axes: { x: false, y1: { position: 'right' } } + } + } + ], + } + }); + + chart.render(); + + expect(fn).toBeCalledTimes(1); + expect(fn).toBeCalledWith(chart, chart.views, PaddingCal); }) }); diff --git a/tests/unit/chart/layout/padding-cal-spec.ts b/tests/unit/chart/layout/padding-cal-spec.ts index c84f9bf24f..601f607852 100644 --- a/tests/unit/chart/layout/padding-cal-spec.ts +++ b/tests/unit/chart/layout/padding-cal-spec.ts @@ -34,4 +34,15 @@ describe('padding-cal', () => { expect(pc.getPadding()).toEqual([16, 8, 16, 8]); }); + + it('get', () => { + expect(PaddingCal.instance().getPadding()).toEqual([0, 0, 0, 0]); + expect(PaddingCal.instance(1, 2, 3, 4).getPadding()).toEqual([1, 2, 3, 4]); + }); + + it('clone', () => { + const pc = PaddingCal.instance(1, 2, 3, 4); + expect(pc.clone().getPadding()).toEqual([1, 2, 3, 4]); + expect(pc.clone()).not.toBe(pc); + }); });