diff --git a/__tests__/integration/snapshots/static/alphabetIntervalFunnel.png b/__tests__/integration/snapshots/static/alphabetIntervalFunnel.png new file mode 100644 index 0000000000..eebac83c24 Binary files /dev/null and b/__tests__/integration/snapshots/static/alphabetIntervalFunnel.png differ diff --git a/__tests__/integration/snapshots/static/alphabetIntervalPyramid.png b/__tests__/integration/snapshots/static/alphabetIntervalPyramid.png new file mode 100644 index 0000000000..965466a7a9 Binary files /dev/null and b/__tests__/integration/snapshots/static/alphabetIntervalPyramid.png differ diff --git a/__tests__/plots/static/alphabet-interval-funnel.ts b/__tests__/plots/static/alphabet-interval-funnel.ts new file mode 100644 index 0000000000..bcdbdab948 --- /dev/null +++ b/__tests__/plots/static/alphabet-interval-funnel.ts @@ -0,0 +1,38 @@ +import { G2Spec } from '../../../src'; + +export function alphabetIntervalFunnel(): G2Spec { + return { + type: 'interval', + coordinate: { + transform: [{ type: 'transpose' }], + }, + data: [ + { text: '页面', value: 1000 }, + { text: '页面1', value: 900 }, + { text: '页面2', value: 800 }, + { text: '页面3', value: 700 }, + ], + transform: [ + { + type: 'symmetryY', + }, + ], + axis: { + x: false, + y: false, + }, + style: { + stroke: '#ff0000', + }, + encode: { + x: 'text', + y: 'value', + color: 'text', + shape: 'funnel', + }, + scale: { + x: { paddingOuter: 0, paddingInner: 0 }, + color: { type: 'ordinal', range: ['red', 'green', 'blue', '#e45ca2'] }, + }, + }; +} diff --git a/__tests__/plots/static/alphabet-interval-pyramid.ts b/__tests__/plots/static/alphabet-interval-pyramid.ts new file mode 100644 index 0000000000..b4c5c6be18 --- /dev/null +++ b/__tests__/plots/static/alphabet-interval-pyramid.ts @@ -0,0 +1,38 @@ +import { G2Spec } from '../../../src'; + +export function alphabetIntervalPyramid(): G2Spec { + return { + type: 'interval', + coordinate: { + transform: [{ type: 'transpose' }], + }, + data: [ + { text: '页面', value: 1000 }, + { text: '页面1', value: 900 }, + { text: '页面2', value: 800 }, + { text: '页面3', value: 700 }, + ], + transform: [ + { + type: 'symmetryY', + }, + ], + axis: { + x: false, + y: false, + }, + style: { + stroke: '#ff0000', + }, + encode: { + x: 'text', + y: 'value', + color: 'text', + shape: 'pyramid', + }, + scale: { + x: { paddingOuter: 0, paddingInner: 0 }, + color: { type: 'ordinal', range: ['red', 'green', 'blue', '#e45ca2'] }, + }, + }; +} diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts index 43a9343a26..e354d3ccb9 100644 --- a/__tests__/plots/static/index.ts +++ b/__tests__/plots/static/index.ts @@ -3,6 +3,8 @@ export { alphabetIntervalTitle } from './alphabet-interval-title'; export { alphabetIntervalLabelOverflowHide } from './alphabet-interval-label-overflow-hide'; export { alphabetIntervalLabelContrastReverse } from './alphabet-interval-label-contrast-reverse'; export { alphabetIntervalDataSort } from './alphabet-interval-data-sort'; +export { alphabetIntervalFunnel } from './alphabet-interval-funnel'; +export { alphabetIntervalPyramid } from './alphabet-interval-pyramid'; export { gammaRandomLineSortXQuantitative } from './gamma-random-line-sortx-quantitative'; export { alphabetIntervalTransposed } from './alphabet-interval-transposed'; export { stateAgesIntervalStacked } from './stateages-interval-stacked'; diff --git a/src/shape/interval/funnel.ts b/src/shape/interval/funnel.ts index 771d6799d0..260e228049 100644 --- a/src/shape/interval/funnel.ts +++ b/src/shape/interval/funnel.ts @@ -1,7 +1,10 @@ +import { Path } from '@antv/g'; +import { line, curveLinearClosed } from 'd3-shape'; import { Coordinate } from '@antv/coord'; import { isTranspose } from '../../utils/coordinate'; import { ShapeComponent as SC, Vector2 } from '../../runtime'; -import { Color } from './color'; +import { select } from '../../utils/selection'; +import { applyStyle, getShapeTheme, reorder, toOpacityKey } from '../utils'; export type FunnelOptions = { adjustPoints?: ( @@ -38,22 +41,30 @@ function getFunnelPoints( export const Funnel: SC = (options) => { const { adjustPoints = getFunnelPoints, ...style } = options; return (points, value, coordinate, theme, point2d, ...args) => { - const { index } = value; + const { index, mark, shape, defaultShape } = value; + const { defaultColor, ...defaults } = getShapeTheme( + theme, + mark, + shape, + defaultShape, + ); const nextPoints = point2d[index + 1]; const funnelPoints = adjustPoints(points, nextPoints, coordinate); + const tpShape = !!isTranspose(coordinate); - return Color({ colorAttribute: 'fill', ...style })( - funnelPoints, - value, - coordinate, - theme, - point2d, - ...args, - ); + const [p0, p1, p2, p3] = tpShape ? reorder(funnelPoints) : funnelPoints; + const { color = defaultColor, opacity } = value; + const b = line().curve(curveLinearClosed)([p0, p1, p2, p3]); + return select(new Path({})) + .call(applyStyle, defaults) + .style('path', b) + .style('fill', color) + .style('fillOpacity', opacity) + .call(applyStyle, style) + .node(); }; }; Funnel.props = { - ...Color.props, - defaultMarker: 'funnel', + defaultMarker: 'square', }; diff --git a/src/shape/interval/pyramid.ts b/src/shape/interval/pyramid.ts index e50318d966..e8731a4c87 100644 --- a/src/shape/interval/pyramid.ts +++ b/src/shape/interval/pyramid.ts @@ -1,7 +1,6 @@ import { Coordinate } from '@antv/coord'; import { isTranspose } from '../../utils/coordinate'; import { ShapeComponent as SC, Vector2 } from '../../runtime'; -import { Color } from './color'; import { Funnel } from './funnel'; export type PyramidOptions = Record; @@ -46,6 +45,5 @@ export const Pyramid: SC = (options) => { }; Pyramid.props = { - ...Color.props, defaultMarker: 'square', };