diff --git a/packages/f2/src/base/component.ts b/packages/f2/src/base/component.ts index ec352c627..eb5663250 100644 --- a/packages/f2/src/base/component.ts +++ b/packages/f2/src/base/component.ts @@ -5,9 +5,9 @@ export interface ComponentContext { [key: string]: any; } -class Component { - props: T; - state: any; +class Component

{ + props: P; + state: S; context: ComponentContext; refs: { [key: string]: any; @@ -21,13 +21,13 @@ class Component { animate: boolean; constructor(props, context?, updater?) { this.props = props; - this.state = {}; + this.state = {} as S; this.context = context; this.updater = updater; } willMount() {} didMount() {} - willReceiveProps(_props: T) {} + willReceiveProps(_props: P) {} willUpdate() {} didUpdate() {} render(): JSX.Element | null { diff --git a/packages/f2/src/chart/index.ts b/packages/f2/src/chart/index.ts index 32fab07c3..f72afd7d3 100644 --- a/packages/f2/src/chart/index.ts +++ b/packages/f2/src/chart/index.ts @@ -1,5 +1,5 @@ import { Scale } from '@antv/scale'; -import { each } from '@antv/util'; +import { each, findIndex, isArray } from '@antv/util'; import Component from '../base/component'; import equal from '../base/equal'; import { applyMixins } from '../mixins'; @@ -35,6 +35,17 @@ interface IChart { props: Props; } +export interface PositionLayout { + position: 'top' | 'right' | 'bottom' | 'left'; + width: number; + height: number; +} + +export interface ComponentPosition { + component: Component; + layout: PositionLayout | PositionLayout[]; +} + // 统计图表 class Chart extends Component implements IChart, InteractionMixin { data: any; @@ -42,6 +53,7 @@ class Chart extends Component implements IChart, InteractionMixin { private layout: Layout; // 坐标系 private coord: Coord; + private componentsPosition: ComponentPosition[] = []; // 交互 interaction: InteractionController; @@ -56,6 +68,7 @@ class Chart extends Component implements IChart, InteractionMixin { constructor(props, context?, updater?) { super(props, context, updater); + const { data, coord: coordOption, scale, interactions = [] } = props; this.layoutController = new LayoutController(); @@ -149,9 +162,10 @@ class Chart extends Component implements IChart, InteractionMixin { }); } - layoutCoord(position, box) { + // 给需要显示的组件留空 + layoutCoord(layout: PositionLayout) { const { coord } = this; - const { width: boxWidth, height: boxHeight } = box; + const { position, width: boxWidth, height: boxHeight } = layout; let { left, top, width, height } = coord; switch (position) { case 'left': @@ -172,6 +186,46 @@ class Chart extends Component implements IChart, InteractionMixin { coord.update({ left, top, width, height }); } + resetCoordLayout() { + const { coord, layout } = this; + coord.update(layout); + } + + updateCoordLayout(layout: PositionLayout | PositionLayout[]) { + if (isArray(layout)) { + layout.forEach((item) => { + this.layoutCoord(item); + }); + return; + } + this.layoutCoord(layout); + } + + updateCoordFor(component: Component, layout: PositionLayout | PositionLayout[]) { + if (!layout) return; + const { componentsPosition } = this; + const componentPosition = { component, layout }; + const existIndex = findIndex(componentsPosition, (item) => { + return item.component === component; + }); + // 说明是已经存在的组件 + if (existIndex > -1) { + componentsPosition.splice(existIndex, 1, componentPosition); + + // 先重置,然后整体重新算一次 + this.resetCoordLayout(); + componentsPosition.forEach((componentPosition) => { + const { layout } = componentPosition; + this.updateCoordLayout(layout); + }); + return; + } + + // 是新组件,直接添加 + componentsPosition.push(componentPosition); + this.updateCoordLayout(layout); + } + getGeometrys() { const { children } = this; const geometrys: Component[] = []; diff --git a/packages/f2/src/components/axis/withAxis.tsx b/packages/f2/src/components/axis/withAxis.tsx index 4f18cc00a..d80c49464 100644 --- a/packages/f2/src/components/axis/withAxis.tsx +++ b/packages/f2/src/components/axis/withAxis.tsx @@ -1,6 +1,7 @@ import { deepMix, isFunction, mix, each, clone, isString, isNumber } from '@antv/util'; import { jsx } from '../../jsx'; import equal from '../../base/equal'; +import { PositionLayout } from '../../chart/index'; import Component from '../../base/component'; import { Style, Tick, AxisProps } from './types'; @@ -10,7 +11,7 @@ type BBox = { }; export default (View) => { - return class Axis extends Component { + return class Axis extends Component { style: Style = {}; constructor(props: AxisProps) { @@ -134,9 +135,7 @@ export default (View) => { const { label, grid } = style; const { label: defaultLabelStyle, grid: defaultGridStyle } = themeAxis; if (isFunction(label)) { - tick.labelStyle = px2hd( - mix({}, defaultLabelStyle, label(tick.text, index, ticks)) - ); + tick.labelStyle = px2hd(mix({}, defaultLabelStyle, label(tick.text, index, ticks))); } if (isFunction(grid)) { tick.gridStyle = px2hd(mix({}, defaultGridStyle, grid(tick.text, index, ticks.length))); @@ -167,37 +166,50 @@ export default (View) => { }); } - // 主要是计算coord的布局 - updateCoord() { + measureLayout(): PositionLayout | PositionLayout[] { const { props } = this; - const { visible, chart, coord } = props; + const { visible, coord } = props; if (visible === false) { - return; + return null; } const ticks = this.getTicks(); const bbox = this.getMaxBBox(ticks, this.style); - const { isPolar, left, top, width: coordWidth, height: coordHeight } = coord; + const { isPolar } = coord; const dimType = this._getDimType(); const { width, height } = bbox; - if (isPolar) { // 机坐标系的 y 不占位置 if (dimType === 'y') { - return; + return null; } - coord.update({ - left: left + width, - top: top + height, - width: coordWidth - width * 2, - height: coordHeight - height * 2, - }); - return; + // 4 个方向都需要留空 + return ['top', 'right', 'bottom', 'left'].map( + (position: 'top' | 'right' | 'bottom' | 'left') => { + return { + position, + width, + height, + }; + } + ); } // 直角坐标系下 const position = this._getPosition(); - chart.layoutCoord(position, bbox); + return { + position, + width, + height, + }; + } + + // 主要是计算coord的布局 + updateCoord() { + const { props } = this; + const { chart } = props; + const layout = this.measureLayout(); + chart.updateCoordFor(this, layout); } render() { diff --git a/packages/f2/src/components/legend/withLegend.tsx b/packages/f2/src/components/legend/withLegend.tsx index c98708c6a..dfcb19a81 100644 --- a/packages/f2/src/components/legend/withLegend.tsx +++ b/packages/f2/src/components/legend/withLegend.tsx @@ -192,7 +192,11 @@ export default (View) => { const { width, height } = style; const marginNumber = context.px2hd(margin); - chart.layoutCoord(position, { width: width + marginNumber, height: height + marginNumber }); + chart.updateCoordFor(this, { + position, + width: width + marginNumber, + height: height + marginNumber, + }); } willMount() {