Skip to content

Commit

Permalink
feat(pie): optimize spider
Browse files Browse the repository at this point in the history
  • Loading branch information
pearmini committed Jul 12, 2024
1 parent bf13fe8 commit 71fa203
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 14 deletions.
2 changes: 2 additions & 0 deletions __tests__/plots/static/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,5 @@ export { stackBarAnnotationStyleText } from './stack-bar-annotation-style-text';
export { githubStarIntervalDarkThemeTransparent } from './github-star-interval-dark-theme-transparent';
export { diamondIntervalGroupX } from './diamond-interval-group-x';
export { mockIntervalSeriesOrder } from './mock-interval-series-order';
export { mockPieSpider } from './mock-pie-spider';
export { mockPieSpiderRight } from './mock-pie-spider-right';
32 changes: 32 additions & 0 deletions __tests__/plots/static/mock-pie-spider-right.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { G2Spec } from '../../../src';

export function mockPieSpiderRight(): 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 },
].reverse(),
encode: {
y: 'value',
color: 'type',
},
labels: [
{
position: 'spider',
text: (obj) => `${obj.type} (${obj.value})`,
labelHeight: 30,
},
],
transform: [{ type: 'stackY' }],
coordinate: { type: 'theta' },
};
}
31 changes: 31 additions & 0 deletions __tests__/plots/static/mock-pie-spider.ts
Original file line number Diff line number Diff line change
@@ -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' },
};
}
7 changes: 4 additions & 3 deletions src/shape/label/label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function getDefaultStyle(
coordinate: Coordinate,
theme: G2Theme,
options: LabelOptions,
labels: Vector2[][],
): Record<string, any> {
// For non-series mark, calc position for label based on
// position and the bounds of shape.
Expand All @@ -48,7 +49,7 @@ function getDefaultStyle(
}
return {
...t,
...processor(p, points, v, coordinate, options),
...processor(p, points, v, coordinate, options, labels),
};
}

Expand All @@ -59,7 +60,7 @@ function getDefaultStyle(
export const Label: SC<LabelOptions> = (options, context) => {
const { coordinate, theme } = context;
const { render } = options;
return (points, value) => {
return (points, value, style, labels) => {
const {
text,
x,
Expand All @@ -73,7 +74,7 @@ export const Label: SC<LabelOptions> = (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)
Expand Down
55 changes: 45 additions & 10 deletions src/shape/label/position/spider.ts
Original file line number Diff line number Diff line change
@@ -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<string, any>,
coordinate: Coordinate,
) {
if (!isCircular(coordinate)) return {};
const { connectorLength, connectorLength2, connectorDistance } = value;

const { ...style }: any = inferOutsideCircularStyle(
'outside',
points,
Expand All @@ -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;
}

function dodgeY(
styles: Record<string, any>[],
options: Record<string, any> = {},
) {
const { labelHeight = 15 } = options;
const sortedStyles = sort(styles, (d) => d.y);
// debugger
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<string, any>,
coordinate: Coordinate,
options: Record<string, any>,
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);
}
17 changes: 16 additions & 1 deletion src/shape/text/advance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
Expand All @@ -178,6 +188,7 @@ export const Advance = createElement((g) => {
transform: labelTransform,
transformOrigin: labelTransformOrigin,
...rest,
dy,
})
.node();
} else {
Expand All @@ -190,6 +201,7 @@ export const Advance = createElement((g) => {
transform: labelTransform,
transformOrigin: labelTransformOrigin,
...rest,
dy,
})
.node();
}
Expand All @@ -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 &&
Expand Down

0 comments on commit 71fa203

Please sign in to comment.