Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

363 lines between labels and slices #2734

Merged
merged 16 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions demo/js/components/victory-pie-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { random, range } from "lodash";
import React from "react";
import { VictoryPie } from "victory-pie";
import { VictoryTooltip } from "victory-tooltip";
import { VictoryTheme } from "victory-core";
import { VictoryTheme, LineSegment } from "victory-core";

export default class App extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -228,7 +228,7 @@ export default class App extends React.Component {
<VictoryPie
style={{ ...this.state.style, labels: { fontSize: 0 } }}
data={this.state.data}
innerRadius={100}
innerRadius={90}
animate={{ duration: 2000 }}
colorScale={this.state.colorScale}
/>
Expand Down Expand Up @@ -317,6 +317,20 @@ export default class App extends React.Component {
{ x: 8, y: 1, l: 315 },
]}
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator={<LineSegment style={{opacity:"1",strokeWidth:"1px",stroke: "red"}}/>}
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator={<LineSegment style={{opacity:"1",strokeWidth:"1px",strokeDasharray: "1",stroke: "red"}}/>}
labelIndicatorInnerOffset={35}
labelIndicatorOuterOffset={4}
/>
</div>
</div>
);
Expand Down
16 changes: 15 additions & 1 deletion demo/ts/components/victory-pie-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { random, range } from "lodash";
import { VictoryPie } from "victory-pie";
import { VictoryTooltip } from "victory-tooltip";
import { VictoryTheme } from "victory-core";
import { VictoryTheme, LineSegment } from "victory-core";

interface VictoryPieDemoState {
data: {
Expand Down Expand Up @@ -306,6 +306,20 @@ export default class VictoryPieDemo extends React.Component<
animate={{ duration: 2000 }}
innerRadius={140}
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator={<LineSegment style={{opacity:"1",strokeWidth:"1px",stroke: "red"}}/>}
/>
<VictoryPie
style={{ parent: parentStyle }}
labelIndicator={<LineSegment style={{opacity:"1",strokeWidth:"1px",strokeDasharray: "1",stroke: "red"}}/>}
labelIndicatorInnerOffset={45}
labelIndicatorOuterOffset={15}
/>
</div>
</div>
);
Expand Down
57 changes: 56 additions & 1 deletion docs/src/content/docs/victory-pie.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ The `labelPosition` prop specifies the position of each label relative to its co

`type: number || function`

The `labelRadius` prop defines the radius of the arc that will be used for positioning each slice label. If this prop is not set, the label radius will default to the radius of the pie + label padding. If this prop is given as a function, it will be evaluated for each label `VictoryPie` renders, and will be evaluated with the props that correspond to that label, as well as the radius and innerRadius of the corresponding slice.
The `labelRadius` prop defines the radius of the arc that will be used for positioning each slice label. If this prop is not set, the label radius will default to the radius of the pie + label padding. If this prop is given as a function, it will be evaluated for each label `VictoryPie` renders, and will be evaluated with the props that correspond to that label, as well as the radius and innerRadius of the corresponding slice. If `labelIndicator` prop is being used, passed `labelRadius`(> radius) is used to calculate the co-ordinates of the outer indicator line. If no specific value for labelRadius is passed , default values will be considered. The outer indicator line length is the difference between `labelRadius` and `labelIndicatorOuterOffset`.

```playground
<VictoryPie
Expand Down Expand Up @@ -519,6 +519,61 @@ See the [Data Accessors Guide][] for more detail on formatting and processing da
y={(d) => d.value + d.error}
```

## labelIndicator

`type: boolean || element`

The `labelIndicator` prop defines the label indicator line between labels and the pie chart. If this prop is used as a boolean,then the default indicator will be displayed. To customize or pass your own styling `<LineSegment/>` can be passed to labelIndicator. LabelIndicator is functional only when labelPosition = "centroid". To adjust the labelIndicator length, `labelIndicatorInnerOffset` and `labelIndicatorOuterOffset` props can be used alongside labelIndicator.

```playground
<VictoryPie
data={sampleData}
labelIndicator
style={{ labels: { fill: "white", fontSize: 20, fontWeight: "bold" } }}
/>
<VictoryPie
data={sampleData}
labelIndicator={<LineSegment style = {{stroke:"red", strokeDasharray:1,fill: "none",}}/>}
style={{ labels: { fill: "white", fontSize: 20, fontWeight: "bold" } }}
/>
<VictoryPie
data={sampleData}
labelIndicator={<LineSegment style = {{stroke:"red", strokeDasharray:1,fill: "none",}}/>}
style={{ labels: { fill: "white", fontSize: 20, fontWeight: "bold" } }}
labelIndicatorInnerOffset={10}
labelIndicatorOuterOffset={15}
/>
```
## labelIndicatorInnerOffset

`type: number`

The `labelIndicatorInnerOffset` prop defines the offset by which the indicator length inside pie chart is being drawn. Higher the number shorter the length.

```playground
<VictoryPie
data={sampleData}
labelIndicator
style={{ labels: { fill: "white", fontSize: 20, fontWeight: "bold" } }}
labelIndicatorInnerOffset={10}
/>
```

## labelIndicatorOuterOffset

`type: number`

The `labelIndicatorOuterOffset` prop defines the offset by which the indicator length outside the pie chart is being drawn. Higher the number shorter the length.

```playground
<VictoryPie
data={sampleData}
labelIndicator
style={{ labels: { fill: "white", fontSize: 20, fontWeight: "bold" } }}
labelIndicatorOuterOffset={10}
/>
```

[animations guide]: /guides/animations
[data accessors guide]: /guides/data-accessors
[custom components guide]: /guides/custom-components
Expand Down
80 changes: 76 additions & 4 deletions packages/victory-pie/src/helper-methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,13 @@ const getLabelText = (props, datum, index) => {
return checkForValidText(text);
};

const getLabelArc = (radius, labelRadius, style) => {
const getLabelArc = (labelRadius) => {
return d3Shape.arc().outerRadius(labelRadius).innerRadius(labelRadius);
};

const getCalculatedLabelRadius = (radius, labelRadius, style) => {
const padding = (style && style.padding) || 0;
const arcRadius = labelRadius || radius + padding;
return d3Shape.arc().outerRadius(arcRadius).innerRadius(arcRadius);
return labelRadius || radius + padding;
};

const getLabelPosition = (arc, slice, position) => {
Expand Down Expand Up @@ -195,7 +198,12 @@ const getLabelProps = (text, dataProps, calculatedValues) => {
labelStyle,
assign({ labelRadius, text }, dataProps),
);
const labelArc = getLabelArc(defaultRadius, labelRadius, evaluatedStyle);
const calculatedLabelRadius = getCalculatedLabelRadius(
defaultRadius,
labelRadius,
evaluatedStyle,
);
const labelArc = getLabelArc(calculatedLabelRadius);
const position = getLabelPosition(labelArc, slice, labelPosition);
const baseAngle = getBaseLabelAngle(slice, labelPosition, labelStyle);
const labelAngle = getLabelAngle(baseAngle, labelPlacement);
Expand All @@ -219,6 +227,7 @@ const getLabelProps = (text, dataProps, calculatedValues) => {
textAnchor,
verticalAnchor,
angle: labelAngle,
calculatedLabelRadius,
};

if (!Helpers.isTooltip(labelComponent)) {
Expand All @@ -228,6 +237,57 @@ const getLabelProps = (text, dataProps, calculatedValues) => {
return defaults({}, labelProps, Helpers.omit(tooltipTheme, ["style"]));
};

export const getXOffsetMultiplayerByAngle = (angle) =>
Math.cos(angle - Helpers.degreesToRadians(90));
export const getYOffsetMultiplayerByAngle = (angle) =>
Math.sin(angle - Helpers.degreesToRadians(90));
export const getXOffset = (offset, angle) =>
offset * getXOffsetMultiplayerByAngle(angle);
export const getYOffset = (offset, angle) =>
offset * getYOffsetMultiplayerByAngle(angle);
export const getAverage = (array) =>
array.reduce((acc, cur) => acc + cur, 0) / array.length;

export const getLabelIndicatorPropsForLineSegment = (
props,
calculatedValues,
labelProps,
) => {
const {
innerRadius,
radius,
slice: { startAngle, endAngle },
labelIndicatorInnerOffset,
labelIndicatorOuterOffset,
index,
} = props;

const { height, width } = calculatedValues;
const { calculatedLabelRadius } = labelProps;
// calculation
const middleRadius = getAverage([innerRadius, radius]);
const midAngle = getAverage([endAngle, startAngle]);
const centerX = width / 2;
const centerY = height / 2;
const innerOffset = middleRadius + labelIndicatorInnerOffset;
const outerOffset = calculatedLabelRadius - labelIndicatorOuterOffset;

const x1 = centerX + getXOffset(innerOffset, midAngle);
const y1 = centerY + getYOffset(innerOffset, midAngle);

const x2 = centerX + getXOffset(outerOffset, midAngle);
const y2 = centerY + getYOffset(outerOffset, midAngle);

const labelIndicatorProps = {
x1,
y1,
x2,
y2,
index,
};
return defaults({}, labelIndicatorProps);
};

export const getBaseProps = (initialProps, fallbackProps) => {
const props = Helpers.modifyProps(initialProps, fallbackProps, "pie");
const calculatedValues = getCalculatedValues(props);
Expand All @@ -248,6 +308,7 @@ export const getBaseProps = (initialProps, fallbackProps) => {
cornerRadius,
padAngle,
disableInlineStyles,
labelIndicator,
} = calculatedValues;
const radius = props.radius || defaultRadius;
const initialChildProps = {
Expand Down Expand Up @@ -288,6 +349,17 @@ export const getBaseProps = (initialProps, fallbackProps) => {
assign({}, props, dataProps),
calculatedValues,
);
if (labelIndicator) {
const labelProps = childProps[eventKey].labels;
if (labelProps.calculatedLabelRadius > radius) {
childProps[eventKey].labelIndicators =
getLabelIndicatorPropsForLineSegment(
assign({}, props, dataProps),
calculatedValues,
labelProps,
);
}
}
}
return childProps;
}, initialChildProps);
Expand Down
3 changes: 3 additions & 0 deletions packages/victory-pie/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export interface VictoryPieProps
>[];
eventKey?: StringOrNumberOrCallback;
innerRadius?: NumberOrCallback;
labelIndicator?: boolean | React.ReactElement;
labelIndicatorInnerOffset: number;
labelIndicatorOuterOffset: number;
labelPlacement?:
| VictorySliceLabelPlacementType
| ((props: SliceProps) => VictorySliceLabelPlacementType);
Expand Down
Loading