From 7610a54015196525ae2d7e3ce8c9634d3f9f99f0 Mon Sep 17 00:00:00 2001 From: pearmini Date: Fri, 12 Jul 2024 17:58:23 +0800 Subject: [PATCH 1/4] feat(pie): optimize spider --- .../snapshots/static/mockPieSpider.svg | 1504 +++++++++++++++++ .../snapshots/static/mockPieSpiderRight.svg | 1504 +++++++++++++++++ .../population2015IntervalSpiderLabel.svg | 45 +- __tests__/plots/static/index.ts | 2 + .../plots/static/mock-pie-spider-right.ts | 32 + __tests__/plots/static/mock-pie-spider.ts | 31 + src/shape/label/label.ts | 7 +- src/shape/label/position/spider.ts | 55 +- src/shape/text/advance.ts | 17 +- 9 files changed, 3162 insertions(+), 35 deletions(-) create mode 100644 __tests__/integration/snapshots/static/mockPieSpider.svg create mode 100644 __tests__/integration/snapshots/static/mockPieSpiderRight.svg create mode 100644 __tests__/plots/static/mock-pie-spider-right.ts create mode 100644 __tests__/plots/static/mock-pie-spider.ts diff --git a/__tests__/integration/snapshots/static/mockPieSpider.svg b/__tests__/integration/snapshots/static/mockPieSpider.svg new file mode 100644 index 0000000000..123a96b0e4 --- /dev/null +++ b/__tests__/integration/snapshots/static/mockPieSpider.svg @@ -0,0 +1,1504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 微博 + + + + + + + + + + + + + + + + + + + + 其他 + + + + + + + + + + + + + + + + + + + + 论坛 + + + + + + + + + + + + + + + + + + + + 网站 + + + + + + + + + + + + + + + + + + + + 微信 + + + + + + + + + + + + + + + + + + + + 客户端 + + + + + + + + + + + + + + + + + + + + 新闻 + + + + + + + + + + + + + + + + + + + + 视频 + + + + + + + + + + + + + + + + + + + + 博客 + + + + + + + + + + + + + + + + + + + + 报刊 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 微博 (93.33) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/mockPieSpiderRight.svg b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg new file mode 100644 index 0000000000..1fae44a203 --- /dev/null +++ b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg @@ -0,0 +1,1504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 报刊 + + + + + + + + + + + + + + + + + + + + 博客 + + + + + + + + + + + + + + + + + + + + 视频 + + + + + + + + + + + + + + + + + + + + 新闻 + + + + + + + + + + + + + + + + + + + + 客户端 + + + + + + + + + + + + + + + + + + + + 微信 + + + + + + + + + + + + + + + + + + + + 网站 + + + + + + + + + + + + + + + + + + + + 论坛 + + + + + + + + + + + + + + + + + + + + 其他 + + + + + + + + + + + + + + + + + + + + 微博 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 微博 (93.33) + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/population2015IntervalSpiderLabel.svg b/__tests__/integration/snapshots/static/population2015IntervalSpiderLabel.svg index 60085e0f3e..6b909b5bc7 100644 --- a/__tests__/integration/snapshots/static/population2015IntervalSpiderLabel.svg +++ b/__tests__/integration/snapshots/static/population2015IntervalSpiderLabel.svg @@ -856,8 +856,8 @@ id="g-svg-97" fill="none" x="36.799999999999955" - y="119.4269445047411" - transform="matrix(1,0,0,1,36.799999,119.426941)" + y="128.38231815400033" + transform="matrix(1,0,0,1,36.799999,128.382324)" class="label" > @@ -890,7 +890,7 @@ @@ -922,6 +922,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" + style="transform:translate(0px, 15.198547989487338px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -935,7 +936,7 @@ @@ -967,6 +968,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" + style="transform:translate(0px, 18.280273103385866px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -980,7 +982,7 @@ @@ -1012,6 +1014,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" + style="transform:translate(0px, 11.519948735978517px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1025,7 +1028,7 @@ @@ -1070,7 +1073,7 @@ `${obj.type} (${obj.value})`, + labelHeight: 30, + }, + ], + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta' }, + }; +} diff --git a/__tests__/plots/static/mock-pie-spider.ts b/__tests__/plots/static/mock-pie-spider.ts new file mode 100644 index 0000000000..14e518d81e --- /dev/null +++ b/__tests__/plots/static/mock-pie-spider.ts @@ -0,0 +1,31 @@ +import { G2Spec } from '../../../src'; + +export function mockPieSpider(): G2Spec { + return { + type: 'interval', + data: [ + { type: '微博', value: 93.33 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '博客', value: 0.37 }, + { type: '报刊', value: 0.17 }, + ], + encode: { + y: 'value', + color: 'type', + }, + labels: [ + { + position: 'spider', + text: (obj) => `${obj.type} (${obj.value})`, + }, + ], + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta' }, + }; +} diff --git a/src/shape/label/label.ts b/src/shape/label/label.ts index 861105d5aa..c5d4b38ac2 100644 --- a/src/shape/label/label.ts +++ b/src/shape/label/label.ts @@ -29,6 +29,7 @@ function getDefaultStyle( coordinate: Coordinate, theme: G2Theme, options: LabelOptions, + labels: Vector2[][], ): Record { // For non-series mark, calc position for label based on // position and the bounds of shape. @@ -48,7 +49,7 @@ function getDefaultStyle( } return { ...t, - ...processor(p, points, v, coordinate, options), + ...processor(p, points, v, coordinate, options, labels), }; } @@ -59,7 +60,7 @@ function getDefaultStyle( export const Label: SC = (options, context) => { const { coordinate, theme } = context; const { render } = options; - return (points, value) => { + return (points, value, style, labels) => { const { text, x, @@ -73,7 +74,7 @@ export const Label: SC = (options, context) => { rotate = 0, transform = '', ...defaultStyle - } = getDefaultStyle(points, value, coordinate, theme, options); + } = getDefaultStyle(points, value, coordinate, theme, options, labels); return select(new Advance()) .call(applyStyle, defaultStyle) diff --git a/src/shape/label/position/spider.ts b/src/shape/label/position/spider.ts index b864368e63..b53c908701 100644 --- a/src/shape/label/position/spider.ts +++ b/src/shape/label/position/spider.ts @@ -1,21 +1,18 @@ import { Coordinate } from '@antv/coord'; +import { sort } from 'd3-array'; import { Vector2 } from '../../../runtime'; import { isCircular } from '../../../utils/coordinate'; import { LabelPosition } from './default'; import { inferOutsideCircularStyle, radiusOf, angleOf } from './outside'; -/** - * Spider label transform only suitable for the labels in polar coordinate, labels should distinguish coordinate type. - */ -export function spider( - position: LabelPosition, +const styleByPoints = new WeakMap(); + +function compute( points: Vector2[], value: Record, coordinate: Coordinate, ) { - if (!isCircular(coordinate)) return {}; const { connectorLength, connectorLength2, connectorDistance } = value; - const { ...style }: any = inferOutsideCircularStyle( 'outside', points, @@ -27,13 +24,51 @@ export function spider( const angle = angleOf(points, value, coordinate); const radius1 = radius + connectorLength + connectorLength2; const sign = Math.sin(angle) > 0 ? 1 : -1; - const newX = center[0] + (radius1 + +connectorDistance) * sign; - const { x: originX } = style; const dx = newX - originX; style.x += dx; style.connectorPoints[0][0] -= dx; - return style; } + +// TODO: optimize +function dodgeY( + styles: Record[], + options: Record = {}, +) { + const { labelHeight = 15 } = options; + const sortedStyles = sort(styles, (d) => d.y); + let preY = -labelHeight; + for (let i = 0; i < sortedStyles.length; ++i) { + const cur = sortedStyles[i]; + const nextY = preY + labelHeight; + const dy = Math.max(0, nextY - cur.y); + cur.labelOffsetY = dy; + preY = cur.y + dy; + } +} + +/** + * Spider label transform only suitable for the labels in polar coordinate, + * labels should distinguish coordinate type. + */ +export function spider( + position: LabelPosition, + points: Vector2[], + value: Record, + coordinate: Coordinate, + options: Record, + labels: Vector2[][], +) { + if (!isCircular(coordinate)) return {}; + if (styleByPoints.has(points)) return styleByPoints.get(points); + const styles = labels.map((points) => compute(points, value, coordinate)); + const { width } = coordinate.getOptions(); + const left = styles.filter((d) => d.x < width / 2); + const right = styles.filter((d) => d.x >= width / 2); + dodgeY(left, options); + dodgeY(right, options); + styles.forEach((style, i) => styleByPoints.set(labels[i], style)); + return styleByPoints.get(points); +} diff --git a/src/shape/text/advance.ts b/src/shape/text/advance.ts index 90f7477210..5ee81571c9 100644 --- a/src/shape/text/advance.ts +++ b/src/shape/text/advance.ts @@ -95,7 +95,9 @@ function inferConnectorPath( shape: DisplayObject, points: Vector2[], controlPoints: Vector2[], - coordCenter, + coordCenter: Vector2, + labelOffset: number, + left = true, ) { const [[x0, y0], [x1, y1]] = points; const [x, y] = getConnectorPoint(shape); @@ -125,6 +127,12 @@ function inferConnectorPath( P.splice(1, 1, [x2, 0]); } + if (labelOffset) { + const prev = P[P.length - 1]; + const prevX = prev[0]; + prev[0] += left ? 4 : -4; + P.push([prevX, labelOffset], [x + (left ? 4 : -4), labelOffset]); + } return line()(P); } @@ -169,6 +177,8 @@ export const Advance = createElement((g) => { let textShape; // Use html to customize advance text. + const labelOffset = rest['labelOffsetY'] || 0; + const dy = (rest.dy || 0) + labelOffset; if (innerHTML) { textShape = select(g) .maybeAppend('html', 'html', className) @@ -178,6 +188,7 @@ export const Advance = createElement((g) => { transform: labelTransform, transformOrigin: labelTransformOrigin, ...rest, + dy, }) .node(); } else { @@ -190,6 +201,7 @@ export const Advance = createElement((g) => { transform: labelTransform, transformOrigin: labelTransformOrigin, ...rest, + dy, }) .node(); } @@ -201,11 +213,14 @@ export const Advance = createElement((g) => { .call(applyStyle, background ? backgroundStyle : {}) .node(); + const left = +x < coordCenter[0]; const connectorPath = inferConnectorPath( rect, endPoints, points, coordCenter, + labelOffset, + left, ); const markerStart = startMarker && From 950f20995d6d37b91811bee15e4d66c206f3e631 Mon Sep 17 00:00:00 2001 From: pearmini Date: Mon, 15 Jul 2024 17:48:44 +0800 Subject: [PATCH 2/4] feat(label): optimize dodgeY --- .../snapshots/static/mockPieSpider.svg | 72 +- .../snapshots/static/mockPieSpiderMany.svg | 2106 +++++++++++++++++ .../snapshots/static/mockPieSpiderRight.svg | 71 +- .../population2015IntervalSpiderLabel.svg | 52 +- __tests__/plots/static/index.ts | 1 + .../plots/static/mock-pie-spider-many.ts | 58 + src/shape/label/position/spider.ts | 33 +- src/shape/label/position/utils.ts | 55 + src/shape/text/advance.ts | 16 +- 9 files changed, 2337 insertions(+), 127 deletions(-) create mode 100644 __tests__/integration/snapshots/static/mockPieSpiderMany.svg create mode 100644 __tests__/plots/static/mock-pie-spider-many.ts create mode 100644 src/shape/label/position/utils.ts diff --git a/__tests__/integration/snapshots/static/mockPieSpider.svg b/__tests__/integration/snapshots/static/mockPieSpider.svg index 123a96b0e4..a31c487220 100644 --- a/__tests__/integration/snapshots/static/mockPieSpider.svg +++ b/__tests__/integration/snapshots/static/mockPieSpider.svg @@ -1094,9 +1094,9 @@ @@ -1107,7 +1107,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 70.71134578737335px);" + style="transform:translate(0px, 55.71134578737335px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1121,7 +1121,7 @@ @@ -1153,7 +1153,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 96.06328442173361px);" + style="transform:translate(0px, 82.06328442173361px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1167,7 +1167,7 @@ @@ -1199,7 +1199,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 94.41975004236903px);" + style="transform:translate(0px, 81.41975004236903px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1213,7 +1213,7 @@ @@ -1245,7 +1245,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 83.02061719898805px);" + style="transform:translate(0px, 71.02061719898805px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1259,7 +1259,7 @@ @@ -1291,7 +1291,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 70.17786459603923px);" + style="transform:translate(0px, 59.17786459603923px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1305,7 +1305,7 @@ @@ -1337,7 +1337,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 56.36642021687919px);" + style="transform:translate(0px, 46.36642021687919px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1351,7 +1351,7 @@ @@ -1383,7 +1383,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 41.80788565113562px);" + style="transform:translate(0px, 32.80788565113562px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1397,7 +1397,7 @@ @@ -1429,7 +1429,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 26.95517806160808px);" + style="transform:translate(0px, 18.95517806160808px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1443,7 +1443,7 @@ @@ -1475,7 +1475,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 11.997430280163002px);" + style="transform:translate(0px, 4.997430280163002px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1489,7 +1489,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 微博 (93.33) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/mockPieSpiderRight.svg b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg index 1fae44a203..0479731651 100644 --- a/__tests__/integration/snapshots/static/mockPieSpiderRight.svg +++ b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg @@ -1049,9 +1049,9 @@ @@ -1062,7 +1062,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 11.99743028016303px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1076,7 +1075,7 @@ @@ -1108,7 +1107,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 41.95517806160811px);" + style="transform:translate(0px, 26.95517806160811px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1122,7 +1121,7 @@ @@ -1154,7 +1153,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 71.80788565113565px);" + style="transform:translate(0px, 56.80788565113565px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1168,7 +1167,7 @@ @@ -1200,7 +1199,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 101.36642021687925px);" + style="transform:translate(0px, 86.36642021687925px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1214,7 +1213,7 @@ @@ -1246,7 +1245,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 130.17786459603934px);" + style="transform:translate(0px, 115.17786459603934px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1260,7 +1259,7 @@ @@ -1292,7 +1291,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 158.02061719898816px);" + style="transform:translate(0px, 143.02061719898816px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1306,7 +1305,7 @@ @@ -1338,7 +1337,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 184.41975004236917px);" + style="transform:translate(0px, 169.41975004236917px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1352,7 +1351,7 @@ @@ -1384,7 +1383,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 201.0632844217336px);" + style="transform:translate(0px, 186.0632844217336px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1398,7 +1397,7 @@ @@ -1430,7 +1429,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 190.71134578737332px);" + style="transform:translate(0px, 175.71134578737332px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1444,7 +1443,7 @@ @@ -890,7 +890,7 @@ @@ -922,7 +922,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 15.198547989487338px);" + style="transform:translate(0px, 5.198547989487338px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -936,7 +936,7 @@ @@ -968,7 +968,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 18.280273103385866px);" + style="transform:translate(0px, 9.280273103385866px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -982,7 +982,7 @@ @@ -1014,7 +1014,7 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 11.519948735978517px);" + style="transform:translate(0px, 3.5199487359785167px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1028,7 +1028,7 @@ @@ -1073,7 +1073,7 @@ `${obj.type} (${obj.value})`, + connectorOpacity: 0.5, + }, + ], + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta' }, + legend: false, + }; +} diff --git a/src/shape/label/position/spider.ts b/src/shape/label/position/spider.ts index b53c908701..1f37356a0c 100644 --- a/src/shape/label/position/spider.ts +++ b/src/shape/label/position/spider.ts @@ -1,9 +1,9 @@ import { Coordinate } from '@antv/coord'; -import { sort } from 'd3-array'; import { Vector2 } from '../../../runtime'; import { isCircular } from '../../../utils/coordinate'; import { LabelPosition } from './default'; import { inferOutsideCircularStyle, radiusOf, angleOf } from './outside'; +import { dodgeY } from './utils'; const styleByPoints = new WeakMap(); @@ -32,23 +32,6 @@ function compute( return style; } -// TODO: optimize -function dodgeY( - styles: Record[], - options: Record = {}, -) { - const { labelHeight = 15 } = options; - const sortedStyles = sort(styles, (d) => d.y); - let preY = -labelHeight; - for (let i = 0; i < sortedStyles.length; ++i) { - const cur = sortedStyles[i]; - const nextY = preY + labelHeight; - const dy = Math.max(0, nextY - cur.y); - cur.labelOffsetY = dy; - preY = cur.y + dy; - } -} - /** * Spider label transform only suitable for the labels in polar coordinate, * labels should distinguish coordinate type. @@ -63,12 +46,12 @@ export function spider( ) { if (!isCircular(coordinate)) return {}; if (styleByPoints.has(points)) return styleByPoints.get(points); - const styles = labels.map((points) => compute(points, value, coordinate)); - const { width } = coordinate.getOptions(); - const left = styles.filter((d) => d.x < width / 2); - const right = styles.filter((d) => d.x >= width / 2); - dodgeY(left, options); - dodgeY(right, options); - styles.forEach((style, i) => styleByPoints.set(labels[i], style)); + const computed = labels.map((points) => compute(points, value, coordinate)); + const { width, height } = coordinate.getOptions(); + const left = computed.filter((d) => d.x < width / 2); + const right = computed.filter((d) => d.x >= width / 2); + dodgeY(left, { ...options, height }); + dodgeY(right, { ...options, height }); + computed.forEach((style, i) => styleByPoints.set(labels[i], style)); return styleByPoints.get(points); } diff --git a/src/shape/label/position/utils.ts b/src/shape/label/position/utils.ts new file mode 100644 index 0000000000..e7287e8304 --- /dev/null +++ b/src/shape/label/position/utils.ts @@ -0,0 +1,55 @@ +import { sort } from 'd3-array'; + +// Optimize antiCollision from: https://github.com/antvis/G2/blob/master/src/geometry/label/layout/pie/util.ts +export function dodgeY( + labels: Record[], + options: Record = {}, +) { + const { labelHeight = 14, height } = options; + + // Sort labels by y and init boxes (one box for each label) + const sortedLabels = sort(labels, (d) => d.y); + const n = sortedLabels.length; + const boxes = new Array(n); + for (let i = 0; i < n; i++) { + const label = sortedLabels[i]; + const { y } = label; + boxes[i] = { y, y1: y + labelHeight, labels: [y] }; + } + + // Merge boxes until no overlapping boxes or only one box left. + // All the boxes should start higher than 0, but maybe higher than height. + let overlap = true; + while (overlap) { + overlap = false; + // Scan backward because boxes maybe deleted. + for (let i = boxes.length - 1; i > 0; i--) { + const box = boxes[i]; + const preBox = boxes[i - 1]; + if (preBox.y1 > box.y) { + overlap = true; + preBox.labels.push(...box.labels); + boxes.splice(i, 1); + + // Compute new y1 to contain the current box. + preBox.y1 += box.y1 - box.y; + + // Make sure the new box is in the range of [0, height]. + const newHeight = preBox.y1 - preBox.y; + preBox.y1 = Math.max(Math.min(preBox.y1, height), newHeight); + preBox.y = preBox.y1 - newHeight; + } + } + } + + let i = 0; + for (const box of boxes) { + const { y, labels } = box; + let prevY = y - labelHeight * 1.5; + for (const label of labels) { + const expectedY = prevY + labelHeight; + sortedLabels[i++].labelOffsetY = Math.max(0, expectedY - label); + prevY += labelHeight; + } + } +} diff --git a/src/shape/text/advance.ts b/src/shape/text/advance.ts index 5ee81571c9..c4aacf9b77 100644 --- a/src/shape/text/advance.ts +++ b/src/shape/text/advance.ts @@ -9,7 +9,7 @@ import { } from '@antv/g'; import { isNumber } from '@antv/util'; import { Marker } from '@antv/component'; -import { line } from 'd3-shape'; +import { line, curveBasis } from 'd3-shape'; import { WithPrefix } from '../../runtime'; import { createElement } from '../../utils/createElement'; import { applyStyle } from '../utils'; @@ -98,6 +98,7 @@ function inferConnectorPath( coordCenter: Vector2, labelOffset: number, left = true, + top = true, ) { const [[x0, y0], [x1, y1]] = points; const [x, y] = getConnectorPoint(shape); @@ -129,9 +130,14 @@ function inferConnectorPath( if (labelOffset) { const prev = P[P.length - 1]; - const prevX = prev[0]; - prev[0] += left ? 4 : -4; - P.push([prevX, labelOffset], [x + (left ? 4 : -4), labelOffset]); + if (top) { + const prevX = prev[0]; + prev[0] += left ? 4 : -4; + P.push([prevX, labelOffset], [x + (left ? 4 : -4), labelOffset]); + } else { + prev[1] = labelOffset; + P.splice(2, 0, [P[1][0], labelOffset]); + } } return line()(P); } @@ -214,6 +220,7 @@ export const Advance = createElement((g) => { .node(); const left = +x < coordCenter[0]; + const top = +y < coordCenter[1]; const connectorPath = inferConnectorPath( rect, endPoints, @@ -221,6 +228,7 @@ export const Advance = createElement((g) => { coordCenter, labelOffset, left, + top, ); const markerStart = startMarker && From 7d67c5cea8fd9908798fda107cf11b85c7f51eb5 Mon Sep 17 00:00:00 2001 From: pearmini Date: Tue, 16 Jul 2024 16:17:21 +0800 Subject: [PATCH 3/4] refactor(spdier): label line --- .../polio-point-stack-enter/interval0-0.svg | 2 +- .../polio-point-stack-enter/interval0-1.svg | 2 +- .../polio-point-stack-enter/interval0-2.svg | 2 +- .../polio-point-stack-enter/interval0-3.svg | 2 +- .../step0.svg | 2 +- .../step1.svg | 2 +- .../indices-line-chart-index-series/step0.svg | 10 +- .../snapshots/static/aaplLineMissingLabel.svg | 12 +- .../acmeCropIncomeIntervalConnector.svg | 18 +- .../alphabetIntervalFunnelConnectorLabel.svg | 16 +- .../static/alphabetIntervalLabelRotate.svg | 10 +- .../static/alphabetIntervalTransposed.svg | 52 +- .../static/blockChainLineAnnotation.svg | 4 +- .../snapshots/static/carsPointScatterPlot.svg | 64 +- .../snapshots/static/energySankeyCustom.svg | 96 +- .../snapshots/static/energySankeyDefaults.svg | 96 +- .../snapshots/static/flareTreeCustom.svg | 504 ++-- .../snapshots/static/flareTreemapCustom.svg | 440 +-- .../static/flareTreemapDrillDown.svg | 6 +- .../static/githubStarIntervalRadialLabel.svg | 6 +- .../snapshots/static/incomeLinkAnnotation.svg | 10 +- .../incomeStatementByRegionIntervalCustom.svg | 18 +- .../snapshots/static/intervalPointBullet.svg | 2 +- .../static/intervalPointBulletDatas.svg | 4 +- .../snapshots/static/intervalPointBullets.svg | 8 +- .../static/marketIntervalMarimekko.svg | 32 +- ...marketIntervalMarimekkoAutoPaddingFlex.svg | 32 +- .../snapshots/static/mockPieSpider.svg | 101 +- .../snapshots/static/mockPieSpiderHide.svg | 2390 +++++++++++++++++ .../snapshots/static/mockPieSpiderMany.svg | 378 ++- .../snapshots/static/mockPieSpiderRight.svg | 100 +- .../snapshots/static/paragraphTextVis.svg | 6 +- .../static/population2015IntervalDonut.svg | 30 +- .../population2015IntervalDonutLabel.svg | 36 +- .../static/population2015IntervalPie.svg | 30 +- .../static/population2015IntervalPieLabel.svg | 36 +- .../population2015IntervalSpiderLabel.svg | 75 +- .../static/populationFlowChordDefault.svg | 16 +- .../static/populationIntervalRoseLabel.svg | 30 +- .../populationIntervalRoseSurroundLabel.svg | 30 +- .../snapshots/static/receiptsLineSlope.svg | 60 +- .../static/vaccinesCellScaleRelation.svg | 4 +- .../worldHistoryIntervalMultiTickCount.svg | 102 +- __tests__/plots/static/index.ts | 1 + .../plots/static/mock-pie-spider-hide.ts | 66 + src/shape/label/position/spider.ts | 7 +- src/shape/label/position/utils.ts | 28 +- src/shape/text/advance.ts | 127 +- 48 files changed, 3770 insertions(+), 1335 deletions(-) create mode 100644 __tests__/integration/snapshots/static/mockPieSpiderHide.svg create mode 100644 __tests__/plots/static/mock-pie-spider-hide.ts diff --git a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-0.svg b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-0.svg index defd8580aa..f6ffc4b63c 100644 --- a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-0.svg +++ b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-0.svg @@ -8158,7 +8158,7 @@ - + diff --git a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-1.svg b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-1.svg index 260a8ca433..40b921bc7d 100644 --- a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-1.svg +++ b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-1.svg @@ -7650,7 +7650,7 @@ - + diff --git a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-2.svg b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-2.svg index 089a4b6fab..839a6f7d61 100644 --- a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-2.svg +++ b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-2.svg @@ -7140,7 +7140,7 @@ - + diff --git a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-3.svg b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-3.svg index 4c64b55fbe..bdc144c3b2 100644 --- a/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-3.svg +++ b/__tests__/integration/snapshots/animation/polio-point-stack-enter/interval0-3.svg @@ -7132,7 +7132,7 @@ - + diff --git a/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step0.svg b/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step0.svg index d4f61e1d42..1f4a4c2242 100644 --- a/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step0.svg +++ b/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step0.svg @@ -2053,7 +2053,7 @@ - + diff --git a/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step1.svg b/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step1.svg index 0428b7c664..952ae5a97f 100644 --- a/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step1.svg +++ b/__tests__/integration/snapshots/interaction/countries-annotation-slider-filter/step1.svg @@ -2070,7 +2070,7 @@ - + diff --git a/__tests__/integration/snapshots/interaction/indices-line-chart-index-series/step0.svg b/__tests__/integration/snapshots/interaction/indices-line-chart-index-series/step0.svg index 4a57afc561..edf8c483be 100644 --- a/__tests__/integration/snapshots/interaction/indices-line-chart-index-series/step0.svg +++ b/__tests__/integration/snapshots/interaction/indices-line-chart-index-series/step0.svg @@ -159,7 +159,7 @@ - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/aaplLineMissingLabel.svg b/__tests__/integration/snapshots/static/aaplLineMissingLabel.svg index b498ea2440..c44b738dd3 100644 --- a/__tests__/integration/snapshots/static/aaplLineMissingLabel.svg +++ b/__tests__/integration/snapshots/static/aaplLineMissingLabel.svg @@ -890,7 +890,7 @@ - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/alphabetIntervalFunnelConnectorLabel.svg b/__tests__/integration/snapshots/static/alphabetIntervalFunnelConnectorLabel.svg index de2e21b70b..8dfe818638 100644 --- a/__tests__/integration/snapshots/static/alphabetIntervalFunnelConnectorLabel.svg +++ b/__tests__/integration/snapshots/static/alphabetIntervalFunnelConnectorLabel.svg @@ -483,7 +483,7 @@ - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/alphabetIntervalLabelRotate.svg b/__tests__/integration/snapshots/static/alphabetIntervalLabelRotate.svg index 3babdacf35..bd86dfb043 100644 --- a/__tests__/integration/snapshots/static/alphabetIntervalLabelRotate.svg +++ b/__tests__/integration/snapshots/static/alphabetIntervalLabelRotate.svg @@ -974,7 +974,7 @@ - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/alphabetIntervalTransposed.svg b/__tests__/integration/snapshots/static/alphabetIntervalTransposed.svg index 5f92bbc411..695d2eff37 100644 --- a/__tests__/integration/snapshots/static/alphabetIntervalTransposed.svg +++ b/__tests__/integration/snapshots/static/alphabetIntervalTransposed.svg @@ -2320,7 +2320,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/blockChainLineAnnotation.svg b/__tests__/integration/snapshots/static/blockChainLineAnnotation.svg index 3415a4a882..e81dac7026 100644 --- a/__tests__/integration/snapshots/static/blockChainLineAnnotation.svg +++ b/__tests__/integration/snapshots/static/blockChainLineAnnotation.svg @@ -957,7 +957,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/energySankeyCustom.svg b/__tests__/integration/snapshots/static/energySankeyCustom.svg index bb822e28a1..e440c57425 100644 --- a/__tests__/integration/snapshots/static/energySankeyCustom.svg +++ b/__tests__/integration/snapshots/static/energySankeyCustom.svg @@ -1424,7 +1424,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/energySankeyDefaults.svg b/__tests__/integration/snapshots/static/energySankeyDefaults.svg index bb83580c8f..b537cb963a 100644 --- a/__tests__/integration/snapshots/static/energySankeyDefaults.svg +++ b/__tests__/integration/snapshots/static/energySankeyDefaults.svg @@ -1335,7 +1335,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/flareTreeCustom.svg b/__tests__/integration/snapshots/static/flareTreeCustom.svg index d0a242a0df..15424cbcf8 100644 --- a/__tests__/integration/snapshots/static/flareTreeCustom.svg +++ b/__tests__/integration/snapshots/static/flareTreeCustom.svg @@ -5391,7 +5391,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/flareTreemapCustom.svg b/__tests__/integration/snapshots/static/flareTreemapCustom.svg index 1cba88495c..ea35a1288c 100644 --- a/__tests__/integration/snapshots/static/flareTreemapCustom.svg +++ b/__tests__/integration/snapshots/static/flareTreemapCustom.svg @@ -4264,7 +4264,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -11737,7 +11737,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/flareTreemapDrillDown.svg b/__tests__/integration/snapshots/static/flareTreemapDrillDown.svg index d89d82ad19..d22e2d5e71 100644 --- a/__tests__/integration/snapshots/static/flareTreemapDrillDown.svg +++ b/__tests__/integration/snapshots/static/flareTreemapDrillDown.svg @@ -458,7 +458,7 @@ - + - + - + diff --git a/__tests__/integration/snapshots/static/githubStarIntervalRadialLabel.svg b/__tests__/integration/snapshots/static/githubStarIntervalRadialLabel.svg index 7495a3f792..9d836c81bb 100644 --- a/__tests__/integration/snapshots/static/githubStarIntervalRadialLabel.svg +++ b/__tests__/integration/snapshots/static/githubStarIntervalRadialLabel.svg @@ -696,7 +696,7 @@ - + - + - + diff --git a/__tests__/integration/snapshots/static/incomeLinkAnnotation.svg b/__tests__/integration/snapshots/static/incomeLinkAnnotation.svg index 0ad155ed7b..e63d8b71a5 100644 --- a/__tests__/integration/snapshots/static/incomeLinkAnnotation.svg +++ b/__tests__/integration/snapshots/static/incomeLinkAnnotation.svg @@ -1407,7 +1407,7 @@ - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/incomeStatementByRegionIntervalCustom.svg b/__tests__/integration/snapshots/static/incomeStatementByRegionIntervalCustom.svg index fd3f4d48fd..66c61fb211 100644 --- a/__tests__/integration/snapshots/static/incomeStatementByRegionIntervalCustom.svg +++ b/__tests__/integration/snapshots/static/incomeStatementByRegionIntervalCustom.svg @@ -1701,7 +1701,7 @@ - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/intervalPointBullet.svg b/__tests__/integration/snapshots/static/intervalPointBullet.svg index 131b5c1401..a89cd78b4e 100644 --- a/__tests__/integration/snapshots/static/intervalPointBullet.svg +++ b/__tests__/integration/snapshots/static/intervalPointBullet.svg @@ -662,7 +662,7 @@ - + diff --git a/__tests__/integration/snapshots/static/intervalPointBulletDatas.svg b/__tests__/integration/snapshots/static/intervalPointBulletDatas.svg index ecced33ba1..8e87528c12 100644 --- a/__tests__/integration/snapshots/static/intervalPointBulletDatas.svg +++ b/__tests__/integration/snapshots/static/intervalPointBulletDatas.svg @@ -707,7 +707,7 @@ - + - + diff --git a/__tests__/integration/snapshots/static/intervalPointBullets.svg b/__tests__/integration/snapshots/static/intervalPointBullets.svg index 4675f1beb3..7ad261d436 100644 --- a/__tests__/integration/snapshots/static/intervalPointBullets.svg +++ b/__tests__/integration/snapshots/static/intervalPointBullets.svg @@ -936,7 +936,7 @@ - + - + - + - + diff --git a/__tests__/integration/snapshots/static/marketIntervalMarimekko.svg b/__tests__/integration/snapshots/static/marketIntervalMarimekko.svg index 09bf0a3eeb..86b2a304aa 100644 --- a/__tests__/integration/snapshots/static/marketIntervalMarimekko.svg +++ b/__tests__/integration/snapshots/static/marketIntervalMarimekko.svg @@ -1616,7 +1616,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/marketIntervalMarimekkoAutoPaddingFlex.svg b/__tests__/integration/snapshots/static/marketIntervalMarimekkoAutoPaddingFlex.svg index 2a341b27bf..9f078d4650 100644 --- a/__tests__/integration/snapshots/static/marketIntervalMarimekkoAutoPaddingFlex.svg +++ b/__tests__/integration/snapshots/static/marketIntervalMarimekkoAutoPaddingFlex.svg @@ -1616,7 +1616,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/mockPieSpider.svg b/__tests__/integration/snapshots/static/mockPieSpider.svg index a31c487220..abdb8d8f9f 100644 --- a/__tests__/integration/snapshots/static/mockPieSpider.svg +++ b/__tests__/integration/snapshots/static/mockPieSpider.svg @@ -1075,7 +1075,7 @@ @@ -1107,7 +1107,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 55.71134578737335px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1121,7 +1120,7 @@ @@ -1153,7 +1152,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 82.06328442173361px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1167,7 +1165,7 @@ @@ -1199,7 +1197,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 81.41975004236903px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1213,7 +1210,7 @@ @@ -1245,7 +1242,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 71.02061719898805px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1259,7 +1255,7 @@ @@ -1291,7 +1287,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 59.17786459603923px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1305,7 +1300,7 @@ @@ -1337,7 +1332,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 46.36642021687919px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1351,7 +1345,7 @@ @@ -1383,7 +1377,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 32.80788565113562px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1397,7 +1390,7 @@ @@ -1429,7 +1422,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 18.95517806160808px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1443,7 +1435,7 @@ @@ -1475,7 +1467,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 4.997430280163002px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1489,7 +1480,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 微博 (93.33) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 其他 (6.67) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 论坛 (4.77) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 网站 (1.44) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 微信 (1.12) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 客户端 (1.05) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 新闻 (0.81) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 视频 (0.39) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 博客 (0.37) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + + 报刊 (0.17) + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/mockPieSpiderMany.svg b/__tests__/integration/snapshots/static/mockPieSpiderMany.svg index 829d6b0d66..8f645a425f 100644 --- a/__tests__/integration/snapshots/static/mockPieSpiderMany.svg +++ b/__tests__/integration/snapshots/static/mockPieSpiderMany.svg @@ -492,7 +492,7 @@ @@ -525,7 +525,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 43.929806541165476px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -539,7 +538,7 @@ @@ -572,7 +571,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 66.6894049338647px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -586,7 +584,7 @@ @@ -619,7 +617,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 75.94274423314516px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -633,7 +630,7 @@ @@ -666,7 +663,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 72.09893324566212px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -680,7 +676,7 @@ @@ -713,7 +709,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 66.94032518105467px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -727,7 +722,7 @@ @@ -760,7 +755,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 60.67549258791229px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -774,7 +768,7 @@ @@ -807,7 +801,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 51.73762845463341px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -821,7 +814,7 @@ @@ -854,7 +847,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 40.971196675266356px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -868,7 +860,7 @@ @@ -901,7 +893,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 29.281235454616876px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -915,7 +906,7 @@ @@ -948,7 +939,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 45.326494596626276px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -962,7 +952,7 @@ @@ -995,7 +985,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 83.7005704675976px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1009,7 +998,7 @@ @@ -1042,7 +1031,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 98.45494100732051px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1056,7 +1044,7 @@ @@ -1089,7 +1077,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 96.24007078922966px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1103,7 +1090,7 @@ @@ -1136,7 +1123,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 92.16519382168008px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1150,7 +1136,7 @@ @@ -1183,7 +1169,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 86.61072134152766px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1197,7 +1182,7 @@ @@ -1230,7 +1215,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 78.02360188272704px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1244,7 +1228,7 @@ @@ -1277,7 +1261,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 67.43556546843516px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1291,7 +1274,7 @@ @@ -1324,7 +1307,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 55.85171665033471px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1338,7 +1320,7 @@ @@ -1371,7 +1353,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 71.75390747032588px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1385,7 +1366,7 @@ @@ -1418,7 +1399,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 103.77356403909425px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1432,7 +1412,7 @@ @@ -1465,7 +1445,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 111.96762081470118px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1479,7 +1458,7 @@ @@ -1512,7 +1491,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 106.43828577043465px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1526,7 +1504,7 @@ @@ -1559,7 +1537,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 99.28393511193684px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1573,7 +1550,7 @@ @@ -1606,7 +1583,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 90.89725098088681px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1620,7 +1596,7 @@ @@ -1653,7 +1629,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 80.39038240899666px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1667,7 +1642,7 @@ @@ -1700,7 +1675,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 68.5495547548303px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1714,7 +1688,7 @@ @@ -1747,7 +1721,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 56.05833647752823px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1761,7 +1734,7 @@ @@ -1794,7 +1767,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 59.27464780967077px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1808,7 +1780,7 @@ @@ -1841,7 +1813,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 65.6364211349744px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1855,7 +1826,7 @@ @@ -1888,7 +1859,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 57.96061673517519px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1902,7 +1872,7 @@ @@ -1935,7 +1905,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 45.56370091987222px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1949,7 +1918,7 @@ @@ -1982,7 +1951,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 32.458391751308966px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1996,7 +1964,7 @@ @@ -2029,12 +1997,12 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 18.884927323129517px);" dx="0.5" fill-opacity="0.65" font-size="12" font-weight="normal" text-anchor="end" + opacity="0" > 新闻 (0.81) @@ -2043,11 +2011,7 @@ @@ -2063,9 +2027,9 @@ @@ -2076,12 +2040,12 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 4.993076266322021px);" dx="0.5" fill-opacity="0.65" font-size="12" font-weight="normal" text-anchor="end" + opacity="0" > 视频 (0.39) @@ -2090,11 +2054,7 @@ diff --git a/__tests__/integration/snapshots/static/mockPieSpiderRight.svg b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg index 0479731651..2ac7d2e30f 100644 --- a/__tests__/integration/snapshots/static/mockPieSpiderRight.svg +++ b/__tests__/integration/snapshots/static/mockPieSpiderRight.svg @@ -1041,17 +1041,17 @@ id="g-svg-152" fill="none" x="534.5" - y="-11.99743028016303" - transform="matrix(1,0,0,1,534.500000,-11.997430)" + y="0" + transform="matrix(1,0,0,1,534.500000,0)" class="label" > @@ -1075,7 +1075,7 @@ @@ -1107,7 +1107,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 26.95517806160811px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1121,7 +1120,7 @@ @@ -1153,7 +1152,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 56.80788565113565px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1167,7 +1165,7 @@ @@ -1199,7 +1197,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 86.36642021687925px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1213,7 +1210,7 @@ @@ -1245,7 +1242,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 115.17786459603934px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1259,7 +1255,7 @@ @@ -1291,7 +1287,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 143.02061719898816px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1305,7 +1300,7 @@ @@ -1337,7 +1332,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 169.41975004236917px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1351,7 +1345,7 @@ @@ -1383,7 +1377,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 186.0632844217336px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1397,7 +1390,7 @@ @@ -1429,7 +1422,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 175.71134578737332px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1443,7 +1435,7 @@ - + - + - + diff --git a/__tests__/integration/snapshots/static/population2015IntervalDonut.svg b/__tests__/integration/snapshots/static/population2015IntervalDonut.svg index 8d516f748b..91620939eb 100644 --- a/__tests__/integration/snapshots/static/population2015IntervalDonut.svg +++ b/__tests__/integration/snapshots/static/population2015IntervalDonut.svg @@ -987,7 +987,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1038,7 +1038,7 @@ @@ -1084,7 +1084,7 @@ @@ -1130,7 +1130,7 @@ @@ -1176,7 +1176,7 @@ @@ -1222,7 +1222,7 @@ @@ -1268,7 +1268,7 @@ @@ -1314,7 +1314,7 @@ @@ -1360,7 +1360,7 @@ @@ -1406,7 +1406,7 @@ @@ -1452,7 +1452,7 @@ @@ -1498,7 +1498,7 @@ @@ -1544,7 +1544,7 @@ @@ -1590,7 +1590,7 @@ @@ -1636,7 +1636,7 @@ @@ -1682,7 +1682,7 @@ @@ -1728,7 +1728,7 @@ @@ -1774,7 +1774,7 @@ diff --git a/__tests__/integration/snapshots/static/population2015IntervalPie.svg b/__tests__/integration/snapshots/static/population2015IntervalPie.svg index 00cd160de7..b6ca704671 100644 --- a/__tests__/integration/snapshots/static/population2015IntervalPie.svg +++ b/__tests__/integration/snapshots/static/population2015IntervalPie.svg @@ -987,7 +987,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -890,7 +890,7 @@ @@ -922,7 +922,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 5.198547989487338px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -936,7 +935,7 @@ @@ -968,7 +967,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 9.280273103385866px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -982,7 +980,7 @@ @@ -1014,7 +1012,6 @@ fill="rgba(29,33,41,1)" dominant-baseline="central" paint-order="stroke" - style="transform:translate(0px, 3.5199487359785167px);" dx="0.5" fill-opacity="0.65" font-size="12" @@ -1028,7 +1025,7 @@ @@ -1073,7 +1070,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/integration/snapshots/static/vaccinesCellScaleRelation.svg b/__tests__/integration/snapshots/static/vaccinesCellScaleRelation.svg index 3c4087d73a..fa268d3700 100644 --- a/__tests__/integration/snapshots/static/vaccinesCellScaleRelation.svg +++ b/__tests__/integration/snapshots/static/vaccinesCellScaleRelation.svg @@ -68972,7 +68972,7 @@ - + - + diff --git a/__tests__/integration/snapshots/static/worldHistoryIntervalMultiTickCount.svg b/__tests__/integration/snapshots/static/worldHistoryIntervalMultiTickCount.svg index 124c50a43e..ed9cb35f4d 100644 --- a/__tests__/integration/snapshots/static/worldHistoryIntervalMultiTickCount.svg +++ b/__tests__/integration/snapshots/static/worldHistoryIntervalMultiTickCount.svg @@ -2218,7 +2218,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts index 721aa9a517..8c83accb7f 100644 --- a/__tests__/plots/static/index.ts +++ b/__tests__/plots/static/index.ts @@ -340,3 +340,4 @@ export { mockIntervalSeriesOrder } from './mock-interval-series-order'; export { mockPieSpider } from './mock-pie-spider'; export { mockPieSpiderRight } from './mock-pie-spider-right'; export { mockPieSpiderMany } from './mock-pie-spider-many'; +export { mockPieSpiderHide } from './mock-pie-spider-hide'; diff --git a/__tests__/plots/static/mock-pie-spider-hide.ts b/__tests__/plots/static/mock-pie-spider-hide.ts new file mode 100644 index 0000000000..4412873a49 --- /dev/null +++ b/__tests__/plots/static/mock-pie-spider-hide.ts @@ -0,0 +1,66 @@ +import { G2Spec } from '../../../src'; + +export function mockPieSpiderHide(): G2Spec { + return { + type: 'interval', + data: [ + { type: '微博', value: 93.33 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '博客', value: 0.37 }, + { type: '报刊', value: 0.17 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '博客', value: 0.37 }, + { type: '报刊', value: 0.17 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '博客', value: 0.37 }, + { type: '报刊', value: 0.17 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + ] + .sort((a, b) => a.value - b.value) + .reverse(), + encode: { + y: 'value', + color: 'type', + }, + labels: [ + { + position: 'spider', + text: (obj) => `${obj.type} (${obj.value})`, + connectorOpacity: 0.5, + }, + ], + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta' }, + legend: false, + }; +} diff --git a/src/shape/label/position/spider.ts b/src/shape/label/position/spider.ts index 1f37356a0c..f993abbf32 100644 --- a/src/shape/label/position/spider.ts +++ b/src/shape/label/position/spider.ts @@ -3,7 +3,7 @@ import { Vector2 } from '../../../runtime'; import { isCircular } from '../../../utils/coordinate'; import { LabelPosition } from './default'; import { inferOutsideCircularStyle, radiusOf, angleOf } from './outside'; -import { dodgeY } from './utils'; +import { hideAndDodgeY } from './utils'; const styleByPoints = new WeakMap(); @@ -50,8 +50,9 @@ export function spider( const { width, height } = coordinate.getOptions(); const left = computed.filter((d) => d.x < width / 2); const right = computed.filter((d) => d.x >= width / 2); - dodgeY(left, { ...options, height }); - dodgeY(right, { ...options, height }); + const extendedOptions = { ...options, height }; + hideAndDodgeY(left, extendedOptions); + hideAndDodgeY(right, extendedOptions); computed.forEach((style, i) => styleByPoints.set(labels[i], style)); return styleByPoints.get(points); } diff --git a/src/shape/label/position/utils.ts b/src/shape/label/position/utils.ts index e7287e8304..e19ca5a13d 100644 --- a/src/shape/label/position/utils.ts +++ b/src/shape/label/position/utils.ts @@ -45,11 +45,33 @@ export function dodgeY( let i = 0; for (const box of boxes) { const { y, labels } = box; - let prevY = y - labelHeight * 1.5; - for (const label of labels) { + let prevY = y - labelHeight; + for (const curY of labels) { + const label = sortedLabels[i++]; const expectedY = prevY + labelHeight; - sortedLabels[i++].labelOffsetY = Math.max(0, expectedY - label); + const dy = expectedY - curY; + label.connectorPoints[0][1] -= dy; + label.y = prevY + labelHeight; prevY += labelHeight; } } } + +export function hideAndDodgeY( + unsorted: Record[], + options: Record, +) { + const labels = sort(unsorted, (d) => d.y); + const { height, labelHeight = 14 } = options; + const maxCount = Math.ceil(height / labelHeight); + if (labels.length <= maxCount) return dodgeY(labels, options); + const filtered = []; + for (let i = 0; i < labels.length; i++) { + // Hide labels out of range. + if (i < labels.length - maxCount) { + labels[i].opacity = 0; + labels[i].connector = false; + } else filtered.push(labels[i]); + } + dodgeY(filtered, options); +} diff --git a/src/shape/text/advance.ts b/src/shape/text/advance.ts index c4aacf9b77..ea0e1e72ad 100644 --- a/src/shape/text/advance.ts +++ b/src/shape/text/advance.ts @@ -9,7 +9,7 @@ import { } from '@antv/g'; import { isNumber } from '@antv/util'; import { Marker } from '@antv/component'; -import { line, curveBasis } from 'd3-shape'; +import { line } from 'd3-shape'; import { WithPrefix } from '../../runtime'; import { createElement } from '../../utils/createElement'; import { applyStyle } from '../utils'; @@ -50,7 +50,7 @@ type TextShapeStyleProps = Omit & text?: string; }; -function getConnectorPoint(shape: GText | Rect) { +function getConnectorPoint(shape: GText | Rect): [number, number] { const { min: [x0, y0], max: [x1, y1], @@ -61,7 +61,6 @@ function getConnectorPoint(shape: GText | Rect) { if (x1 < 0) x = x1; if (y0 > 0) y = y0; if (y1 < 0) y = y1; - return [x, y]; } @@ -91,55 +90,76 @@ const cos = (p0: Vector2, p1: Vector2, p2: Vector2) => { return (a ** 2 + b ** 2 - c ** 2) / (2 * a * b); }; +// A path from element to label. +// Adapted drawLabelLine from https://github.com/antvis/G2/blob/master/src/geometry/label/layout/pie/spider.ts function inferConnectorPath( shape: DisplayObject, - points: Vector2[], - controlPoints: Vector2[], + end: Vector2, + control: Vector2[], coordCenter: Vector2, - labelOffset: number, left = true, top = true, ) { - const [[x0, y0], [x1, y1]] = points; - const [x, y] = getConnectorPoint(shape); - // Straight connector line. - if (x0 === x1 && y0 === y1) { - return line()([ - [0, 0], - [x, y], - ]); - } + const path = (points) => line()(points); - const P: any = [[x0 - x1, y0 - y1]].concat( - controlPoints.length ? controlPoints : [[0, 0]], - ); + if (!end[0] && !end[1]) return path([getConnectorPoint(shape), end]); + if (!control.length) return path([[0, 0], end]); - const p0 = [coordCenter[0] - x1, coordCenter[1] - y1] as Vector2; - const [p1, p2] = P; - // If angle is smaller than 90, which will cause connector overlap with element. - if (cos(p0, p1, p2) > 0) { - const x2 = (() => { - const { min, max } = shape.getLocalBounds(); - // A(x1,y2) perpendicular to B(x2,y2) => x1*x2 + y1*y2 = 0 - const vx = p1[0] + ((p1[1] - p0[1]) * (p1[1] - 0)) / (p1[0] - p0[0]); - if (max[0] < p0[0]) return Math.min(max[0], vx); - return Math.max(min[0], vx); - })(); - P.splice(1, 1, [x2, 0]); - } + const [inflection, start] = control; + const p1 = [...start]; + const p2 = [...inflection]; + + // Label has been adjusted, so add offset to the label. + if (start[0] !== inflection[0]) { + const offset = left ? -4 : 4; + p1[1] = start[1]; + + // For the label in the first quadrant. + if (top && !left) { + p1[0] = Math.max(inflection[0], start[0] - offset); + if (start[1] < inflection[1]) { + p2[1] = p1[1]; + } else { + p2[1] = inflection[1]; + p2[0] = Math.max(p2[0], p1[0] - offset); + } + } - if (labelOffset) { - const prev = P[P.length - 1]; - if (top) { - const prevX = prev[0]; - prev[0] += left ? 4 : -4; - P.push([prevX, labelOffset], [x + (left ? 4 : -4), labelOffset]); - } else { - prev[1] = labelOffset; - P.splice(2, 0, [P[1][0], labelOffset]); + // For the label in the second quadrant. + if (!top && !left) { + p1[0] = Math.max(inflection[0], start[0] - offset); + if (start[1] > inflection[1]) { + p2[1] = p1[1]; + } else { + p2[1] = inflection[1]; + p2[0] = Math.max(p2[0], p1[0] - offset); + } + } + + // For the label in the third quadrant. + if (!top && left) { + p1[0] = Math.min(inflection[0], start[0] - offset); + if (start[1] > inflection[1]) { + p2[1] = p1[1]; + } else { + p2[1] = inflection[1]; + p2[0] = Math.min(p2[0], p1[0] - offset); + } + } + + // For the label in the fourth quadrant. + if (top && left) { + p1[0] = Math.min(inflection[0], start[0] - offset); + if (start[1] < inflection[1]) { + p2[1] = p1[1]; + } else { + p2[1] = inflection[1]; + p2[0] = Math.min(p2[0], p1[0] - offset); + } } } - return line()(P); + + return path([start, p1, p2, inflection, end]); } export const Advance = createElement((g) => { @@ -175,16 +195,12 @@ export const Advance = createElement((g) => { } const { padding, ...backgroundStyle } = subObject(rest, 'background'); - const { points = [], ...connectorStyle } = subObject(rest, 'connector'); - const endPoints: Vector2[] = [ - [+x0, +y0], - [+x, +y], - ]; + const { points: controlPoints = [], ...connectorStyle } = subObject( + rest, + 'connector', + ); let textShape; - // Use html to customize advance text. - const labelOffset = rest['labelOffsetY'] || 0; - const dy = (rest.dy || 0) + labelOffset; if (innerHTML) { textShape = select(g) .maybeAppend('html', 'html', className) @@ -194,7 +210,6 @@ export const Advance = createElement((g) => { transform: labelTransform, transformOrigin: labelTransformOrigin, ...rest, - dy, }) .node(); } else { @@ -207,7 +222,6 @@ export const Advance = createElement((g) => { transform: labelTransform, transformOrigin: labelTransformOrigin, ...rest, - dy, }) .node(); } @@ -219,17 +233,18 @@ export const Advance = createElement((g) => { .call(applyStyle, background ? backgroundStyle : {}) .node(); - const left = +x < coordCenter[0]; - const top = +y < coordCenter[1]; + const left = +x0 < coordCenter[0]; + const top = +y0 < coordCenter[1]; + const end: [number, number] = [+x0 - +x, +y0 - +y]; const connectorPath = inferConnectorPath( rect, - endPoints, - points, + end, + controlPoints, coordCenter, - labelOffset, left, top, ); + const markerStart = startMarker && new Marker({ From f1f4983f33499db9c674feb89a6719000c51081d Mon Sep 17 00:00:00 2001 From: pearmini Date: Tue, 16 Jul 2024 16:31:27 +0800 Subject: [PATCH 4/4] docs(spider): add examples --- site/examples/general/pie/demo/meta.json | 8 ++++ .../general/pie/demo/spider-label-overlap.ts | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 site/examples/general/pie/demo/spider-label-overlap.ts diff --git a/site/examples/general/pie/demo/meta.json b/site/examples/general/pie/demo/meta.json index 422e7b5e50..eb03d66ec8 100644 --- a/site/examples/general/pie/demo/meta.json +++ b/site/examples/general/pie/demo/meta.json @@ -60,6 +60,14 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*gC20SLxWVicAAAAAAAAAAAAADmJ7AQ/original" }, + { + "filename": "spider-label-overlap.ts", + "title": { + "zh": "调整蜘蛛布局", + "en": "Adjust Spider Layout" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*JuJwSJRS4yQAAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "point-jitter-radial.ts", "title": { diff --git a/site/examples/general/pie/demo/spider-label-overlap.ts b/site/examples/general/pie/demo/spider-label-overlap.ts new file mode 100644 index 0000000000..54337a7ad1 --- /dev/null +++ b/site/examples/general/pie/demo/spider-label-overlap.ts @@ -0,0 +1,37 @@ +/** + * A recreation of this demo: https://nivo.rocks/pie/ + */ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', +}); + +chart; + +chart + .interval() + .data([ + { type: '微博', value: 93.33 }, + { type: '其他', value: 6.67 }, + { type: '论坛', value: 4.77 }, + { type: '网站', value: 1.44 }, + { type: '微信', value: 1.12 }, + { type: '客户端', value: 1.05 }, + { type: '新闻', value: 0.81 }, + { type: '视频', value: 0.39 }, + { type: '博客', value: 0.37 }, + { type: '报刊', value: 0.17 }, + ]) + .encode('y', 'value') + .encode('color', 'type') + .transform({ type: 'stackY' }) + .coordinate({ type: 'theta' }) + .animate('enter', { type: 'waveIn' }) + .label({ + position: 'spider', + text: (d) => `${d.type} (${d.value})`, + }) + .legend(false); + +chart.render();