diff --git a/packages/f2/src/chart/index.ts b/packages/f2/src/chart/index.ts index 3f4b66eda..785f05bc3 100644 --- a/packages/f2/src/chart/index.ts +++ b/packages/f2/src/chart/index.ts @@ -229,6 +229,7 @@ class Chart extends Component implements IChart, InteractionMixin { getGeometrys() { const { children } = this; const geometrys: Component[] = []; + // @ts-ignore Children.toArray(children).forEach((element) => { if (!element) return false; const { component } = element; diff --git a/packages/f2/src/components/geometry/index.tsx b/packages/f2/src/components/geometry/index.tsx index 6ad4cd7ef..771837d94 100644 --- a/packages/f2/src/components/geometry/index.tsx +++ b/packages/f2/src/components/geometry/index.tsx @@ -433,14 +433,15 @@ class Geometry extends Component { return this.getAttr('y').scale; } - _getSnap(scale, invertPointX) { - if (scale.isCategory) { - return scale.invert(invertPointX); + _getXSnap(invertPointX) { + const xScale = this.getXScale(); + if (xScale.isCategory) { + return xScale.invert(invertPointX); } // linear 类型 - const invertValue = scale.invert(invertPointX); - const values = scale.values; + const invertValue = xScale.invert(invertPointX); + const values = xScale.values; const len = values.length; // 如果只有1个点直接返回第1个点 if (len === 1) { @@ -466,6 +467,24 @@ class Geometry extends Component { return null; } + _getYSnapRecords(invertPointY, records) { + const yScale = this.getYScale(); + const { field: yField } = yScale; + const yValue = yScale.invert(invertPointY); + // category + if (yScale.isCategory) { + return records.filter((record) => record[FIELD_ORIGIN][yField] === yValue); + } + // linear + return records.filter((record) => { + const rangeY = record[yField]; + if (rangeY[0] <= yValue && rangeY[1] >= yValue) { + return true; + } + return false; + }); + } + // 把 records 拍平 flatRecords() { const { records } = this; @@ -476,7 +495,7 @@ class Geometry extends Component { getSnapRecords(point) { const { props } = this; - const { coord } = props; + const { coord, adjust } = props; const invertPoint = coord.invertPoint(point); const xScale = this.getXScale(); const yScale = this.getYScale(); @@ -486,14 +505,24 @@ class Geometry extends Component { return []; } + const records = this.flatRecords(); + + // 处理饼图 + if (adjust === 'stack' && coord.isPolar && coord.transposed) { + // 弧度在半径范围内 + if (invertPoint.x >= 0 && invertPoint.x <= 1) { + const snapRecords = this._getYSnapRecords(invertPoint.y, records); + return snapRecords; + } + } + const rst = []; - const value = this._getSnap(xScale, invertPoint.x); + const value = this._getXSnap(invertPoint.x); if (!value) { return rst; } const { field: xField } = xScale; const { field: yField } = yScale; - const records = this.flatRecords(); for (let i = 0, len = records.length; i < len; i++) { const record = { ...records[i], @@ -507,6 +536,7 @@ class Geometry extends Component { rst.push(record); } } + return rst; } diff --git a/packages/f2/src/coord/polar.ts b/packages/f2/src/coord/polar.ts index e86c6ec00..cacfc973e 100644 --- a/packages/f2/src/coord/polar.ts +++ b/packages/f2/src/coord/polar.ts @@ -1,5 +1,6 @@ import Base from './base'; import { Range, Option } from './types'; +import { Vector2, Matrix } from '@antv/f2-graphic'; interface PolarOption extends Option { radius: number; // 内半径比例 @@ -64,6 +65,43 @@ class Polar extends Base { y: center.y + Math.sin(angle) * radius, }; } + + invertPoint(point) { + const { center, transposed, x: rangeX, y: rangeY } = this; + const x = { start: rangeX[0], end: rangeX[1] } + const y = { start: rangeY[0], end: rangeY[1] } + const xDim = transposed ? 'y' : 'x'; + const yDim = transposed ? 'x' : 'y'; + + const m = [1, 0, 0, 1, 0, 0]; + Matrix.rotate(m, m, x.start); + + let startV = [1, 0]; + Vector2.transformMat2d(startV, startV, m); + startV = [startV[0], startV[1]]; + + const pointV = [point.x - center.x, point.y - center.y]; + if (Vector2.zero(pointV)) { + return { + x: 0, + y: 0 + }; + } + + let theta = Vector2.angleTo(startV, pointV, x.end < x.start); + if (Math.abs(theta - Math.PI * 2) < 0.001) { + theta = 0; + } + const l = Vector2.length(pointV); + let percentX = theta / (x.end - x.start); + percentX = x.end - x.start > 0 ? percentX : -percentX; + const percentY = (l - y.start) / (y.end - y.start); + const rst = {}; + rst[xDim] = percentX; + rst[yDim] = percentY; + return rst; + } + } export default Polar; diff --git "a/packages/f2/test/components/interval/example/__image_snapshots__/pie-test-tsx-\351\245\274\345\233\276-\351\245\274\345\233\276-\344\272\244\344\272\222\345\274\217label-1-snap.png" "b/packages/f2/test/components/interval/example/__image_snapshots__/pie-test-tsx-\351\245\274\345\233\276-\351\245\274\345\233\276-\344\272\244\344\272\222\345\274\217label-1-snap.png" new file mode 100644 index 000000000..f43bc32d0 Binary files /dev/null and "b/packages/f2/test/components/interval/example/__image_snapshots__/pie-test-tsx-\351\245\274\345\233\276-\351\245\274\345\233\276-\344\272\244\344\272\222\345\274\217label-1-snap.png" differ diff --git a/packages/f2/test/components/interval/example/pie.test.tsx b/packages/f2/test/components/interval/example/pie.test.tsx index 7deb456fe..af1459082 100644 --- a/packages/f2/test/components/interval/example/pie.test.tsx +++ b/packages/f2/test/components/interval/example/pie.test.tsx @@ -1,8 +1,61 @@ import { jsx } from '../../../../src'; import { Polar, Rect } from '../../../../src/coord'; -import { Canvas, Chart } from '../../../../src'; -import { Interval, Legend } from '../../../../src/components'; -import { createContext, delay } from '../../../util'; +import { isArray } from '@antv/util'; +import { Canvas, Chart, Component } from '../../../../src'; +import { Interval } from '../../../../src/components'; +import { createContext, delay, gestureSimulator } from '../../../util'; + +// @ts-ignore +class Test extends Component { + constructor(props) { + super(props); + this.state = { + record: null, + }; + } + didMount() { + super.didMount(); + this._initEvent(); + } + + _handleEvent = (ev) => { + const { chart } = this.props; + const point = ev.points[0]; + const pieData = chart.getSnapRecords(point); + if (isArray(pieData) && pieData.length > 0) { + this.setState({ record: pieData[0] }); + } + }; + + _initEvent() { + const { context } = this; + const { canvas } = context; + canvas.on('click', this._handleEvent); + } + + render() { + if (!this.state.record) { + return null; + } + const { record } = this.state; + const { coord } = this.props; + const { x, y } = coord?.center; + const { radius } = coord; + + const { xMax, xMin } = record; + return ( + + ); + } +} const data = [ { @@ -70,4 +123,39 @@ describe('饼图', () => { await delay(1000); expect(context).toMatchImageSnapshot(); }); + + it('饼图-交互式label', async () => { + const context = createContext('饼图-交互式label'); + const chartRef = { current: null }; + const { type, props } = ( + + + + + + + ); + + const canvas = new Canvas(props); + canvas.render(); + + await gestureSimulator(context.canvas, 'click', { x: 205, y: 76 }); + await delay(1000); + expect(context).toMatchImageSnapshot(); + }); });