Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

Polar Charts #240

Merged
merged 34 commits into from
Jun 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b0b7a80
circle component for polar charts
boygirl Apr 19, 2017
f65e0bc
Merge branch 'experiment/polar' of https://github.com/FormidableLabs/…
boygirl May 4, 2017
93a13ee
clean up Circle
boygirl May 4, 2017
f764425
add arc
boygirl May 4, 2017
c9b4dc7
fix arc rendering
boygirl May 4, 2017
6115ed7
support radial curve and area
boygirl May 5, 2017
de12347
sync angles
boygirl May 5, 2017
1c8bb3b
remove unused circle
boygirl May 9, 2017
7756d85
merge master
boygirl May 15, 2017
bb3d33a
symmetric domain for polar, more polar helpers
boygirl May 16, 2017
ff99e21
safety commit
boygirl May 17, 2017
db32ead
new automatic bar width calculation, polar bars
boygirl May 18, 2017
8941ed9
better default bar widths
boygirl May 19, 2017
6f5e0d2
add a closed option for curves
boygirl May 22, 2017
1042b03
Merge branch 'master' into experiment/polar
boygirl May 24, 2017
c7e07c3
transform primitives to match origin
boygirl May 27, 2017
50d44f2
remove transforms
boygirl May 27, 2017
9ec8fde
polar animations
boygirl May 28, 2017
1064524
animation tweak
boygirl May 28, 2017
5d93c8b
fix bar width scaling
boygirl May 31, 2017
fb3702a
clean up transitions, helpers
boygirl May 31, 2017
75b56a7
tweaks for partial polar charts
boygirl Jun 1, 2017
096d157
translate primitives
boygirl Jun 2, 2017
15e5b0d
add shared label helpers
boygirl Jun 3, 2017
7d9414b
add polar calcs
boygirl Jun 3, 2017
b3518bd
clean up label helpers
boygirl Jun 4, 2017
f3a88fd
support voronoi
boygirl Jun 4, 2017
03ece49
invert polar coordinates
boygirl Jun 4, 2017
1903267
circular clip container
boygirl Jun 5, 2017
21bbf68
fix label placement for tooltips
boygirl Jun 6, 2017
fb05ffa
default label placement for polar charts
boygirl Jun 6, 2017
a788260
lint, fix specs
boygirl Jun 6, 2017
a745f1c
make closed polar curves default
boygirl Jun 6, 2017
893092d
update changelog, tidy
boygirl Jun 6, 2017
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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
VictoryCore Changelog
=====================

## 16.0.0 (2017-06-06)

-[240](https://github.com/FormidableLabs/victory-core/pull/240) Polar Charts

*Breaking Changes*
- Removes default bar width from themes
- Changes how default bar widths are calculated
- Changes render methods for `Area`, `Bar` and `Curve` primitives (Breaking change for `victory-native` and others extending primitives)
- Changes function sigintures for `Selection.getDomainCoordinates` and `Selection.getDataCoordinates` (Breaking change for `victory-native`)

*Features*
- Adds a new `Arc` primitive which is used for polar axes and grid lines
- Adds `polar` and `origin` props to rendered components (primitives, `VictoryLabel`, `VictoryClipContainer` `VictoryContainer`)
- Supports radial areas for `Area` and `Curve`. These props have no effect for cartesian charts
- Adds an `openPath` prop for `Curve`. This prop is used to determine whether radial curves should be closed. Curves are closed by default, but when this prop is set to true they will not be. This prop has no effect for cartesian charts
- Supports polar bars in the `Bar` primitive. (Angular bars only, radial bars are not yet supported)
- Adds a `labelPlacement` prop to `VictoryLabel` and `VictoryTooltip`. Values are "parallel", "perpendicular", and "vertical". These flags help to appropriately position labels in polar charts. Polar charts will use "parallel" label placement by default. Cartesian charts will only use "'vertical" placement.
- Adds support for circular clipPath
- Adds support for polar animation transitions for continuous chart types. During `onLoad`, all points grow from zero. During `onEnter` and `onExit` new points are added / removed at the location of an adjacent point to keep path interpolation as smooth as possible. This implementation obviates the need for radial clip-path animations for these chart types.
- `before` and `after` callbacks for `onLoad`, `onEnter` and `onExit` are now called with `datum`, `index`, and `data` instead of only `datum`.
- Adds `LabelHelpers`
- Adds helper methods for polar charts

## 15.2.0 (2017-05-22)

-[244](https://github.com/FormidableLabs/victory-core/pull/244) Passes missing `datum` and `index` props to `Flyout`
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"dependencies": {
"builder": "^3.2.1",
"builder-victory-component": "^4.0.2",
"builder-victory-component": "^4.0.4",
"d3-ease": "^1.0.0",
"d3-interpolate": "^1.1.1",
"d3-scale": "^1.0.0",
Expand All @@ -36,7 +36,7 @@
"lodash": "^4.17.4"
},
"devDependencies": {
"builder-victory-component-dev": "^4.0.2",
"builder-victory-component-dev": "^4.0.4",
"chai": "^3.5.0",
"enzyme": "^2.4.1",
"mocha": "^3.0.2",
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as VictoryLegend } from "./victory-legend/victory-legend";
export { default as VictoryTooltip } from "./victory-tooltip/victory-tooltip";
export { default as VictoryPortal } from "./victory-portal/victory-portal";
export { default as Portal } from "./victory-portal/portal";
export { default as Arc } from "./victory-primitives/arc";
export { default as Area } from "./victory-primitives/area";
export { default as Bar } from "./victory-primitives/bar";
export { default as Candle } from "./victory-primitives/candle";
Expand All @@ -27,6 +28,7 @@ export { default as DefaultTransitions } from "./victory-util/default-transition
export { default as Domain } from "./victory-util/domain";
export { default as Events } from "./victory-util/events";
export { default as Helpers } from "./victory-util/helpers";
export { default as LabelHelpers } from "./victory-util/label-helpers";
export { default as Log } from "./victory-util/log";
export { default as PropTypes } from "./victory-util/prop-types";
export { default as Scale } from "./victory-util/scale";
Expand Down
12 changes: 6 additions & 6 deletions src/victory-clip-container/victory-clip-container.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import PropTypes from "prop-types";
import { defaults, isFunction } from "lodash";
import { assign, defaults, isFunction } from "lodash";
import ClipPath from "../victory-primitives/clip-path";

export default class VictoryClipContainer extends React.Component {
Expand All @@ -20,6 +20,9 @@ export default class VictoryClipContainer extends React.Component {
clipPathComponent: PropTypes.element,
clipWidth: PropTypes.number,
events: PropTypes.object,
origin: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
polar: PropTypes.bool,
radius: PropTypes.bool,
style: PropTypes.object,
transform: PropTypes.string,
translateX: PropTypes.number,
Expand Down Expand Up @@ -71,12 +74,9 @@ export default class VictoryClipContainer extends React.Component {

// Overridden in victory-core-native
renderClipComponent(props, clipId) {
const {
clipPadding, translateX, translateY, clipHeight, clipWidth, clipPathComponent
} = props;
return React.cloneElement(
clipPathComponent,
{ clipPadding, clipId, translateX, translateY, clipWidth, clipHeight }
props.clipPathComponent,
assign({}, props, { clipId })
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/victory-container/victory-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default class VictoryContainer extends React.Component {
desc: PropTypes.string,
events: PropTypes.object,
height: PropTypes.number,
origin: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
polar: PropTypes.bool,
portalComponent: PropTypes.element,
responsive: PropTypes.bool,
style: PropTypes.object,
Expand Down
26 changes: 24 additions & 2 deletions src/victory-label/victory-label.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*eslint no-magic-numbers: ["error", { "ignore": [0, 0.5, 1, 2] }]*/
import React from "react";
import PropTypes from "prop-types";
import VictoryPortal from "../victory-portal/victory-portal";
import CustomPropTypes from "../victory-util/prop-types";
import Collection from "../victory-util/collection";
import Helpers from "../victory-util/helpers";
import LabelHelpers from "../victory-util/label-helpers";
import Style from "../victory-util/style";
import Log from "../victory-util/log";
import { assign, merge } from "lodash";
Expand Down Expand Up @@ -46,11 +46,14 @@ export default class VictoryLabel extends React.Component {
]),
events: PropTypes.object,
index: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
labelPlacement: PropTypes.oneOf(["parallel", "perpendicular", "vertical"]),
lineHeight: PropTypes.oneOfType([
PropTypes.string,
CustomPropTypes.nonNegative,
PropTypes.func
]),
origin: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
polar: PropTypes.bool,
renderInPortal: PropTypes.bool,
style: PropTypes.oneOfType([
PropTypes.object,
Expand Down Expand Up @@ -197,14 +200,33 @@ export default class VictoryLabel extends React.Component {

getTransform(props, style) {
const { datum, x, y } = props;
const angle = style.angle || props.angle;
const angle = style.angle || props.angle || this.getDefaultAngle(props);
const transform = props.transform || style.transform;
const transformPart = transform && Helpers.evaluateProp(transform, datum);
const rotatePart = angle && { rotate: [angle, x, y] };
return transformPart || angle ?
Style.toTransformString(transformPart, rotatePart) : undefined;
}

getDefaultAngle(props) {
const { polar, labelPlacement, datum } = props;
if (!polar || !labelPlacement || labelPlacement === "vertical") {
return 0;
}
const degrees = LabelHelpers.getDegrees(props, datum);
const sign = (degrees > 90 && degrees < 180 || degrees > 270) ? 1 : -1;
let angle;
if (degrees === 0 || degrees === 180) {
angle = 90;
} else if (degrees > 0 && degrees < 180) {
angle = 90 - degrees;
} else if (degrees > 180 && degrees < 360) {
angle = 270 - degrees;
}
const labelRotation = labelPlacement === "perpendicular" ? 0 : 90;
return angle + sign * labelRotation;
}

getFontSize(style) {
const baseSize = style && style.fontSize;
if (typeof baseSize === "number") {
Expand Down
80 changes: 80 additions & 0 deletions src/victory-primitives/arc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2, 180] }]*/
import React from "react";
import PropTypes from "prop-types";
import Helpers from "../victory-util/helpers";
import { assign, isEqual } from "lodash";
import CommonProps from "./common-props";

export default class Arc extends React.Component {
static propTypes = {
...CommonProps,
closedPath: PropTypes.bool,
cx: PropTypes.number,
cy: PropTypes.number,
datum: PropTypes.any,
endAngle: PropTypes.number,
r: PropTypes.number,
startAngle: PropTypes.number
};

componentWillMount() {
this.style = this.getStyle(this.props);
}

shouldComponentUpdate(nextProps) {
const { cx, cy, r } = this.props;
const style = this.getStyle(nextProps);
if (cx !== nextProps.cx || cy !== nextProps.cy || r !== nextProps.r) {
this.style = style;
return true;
}
if (!isEqual(style, this.style)) {
this.style = style;
return true;
}
return false;
}

getStyle(props) {
const { style, datum, active } = props;
return Helpers.evaluateStyle(assign({ stroke: "black", fill: "none" }, style), datum, active);
}

getArcPath(props) {
const { cx, cy, r, startAngle, endAngle, closedPath } = props;
// Always draw the path as two arcs so that complete circles may be rendered.
const halfAngle = (Math.abs(endAngle - startAngle) / 2) + startAngle;
const x1 = cx + r * Math.cos(Helpers.degreesToRadians(startAngle));
const y1 = cy - r * Math.sin(Helpers.degreesToRadians(startAngle));
const x2 = cx + r * Math.cos(Helpers.degreesToRadians(halfAngle));
const y2 = cy - r * Math.sin(Helpers.degreesToRadians(halfAngle));
const x3 = cx + r * Math.cos(Helpers.degreesToRadians(endAngle));
const y3 = cy - r * Math.sin(Helpers.degreesToRadians(endAngle));
const largerArcFlag1 = halfAngle - startAngle <= 180 ? 0 : 1;
const largerArcFlag2 = endAngle - halfAngle <= 180 ? 0 : 1;
const arcStart = closedPath ? ` M ${cx}, ${cy} L ${x1}, ${y1}` : `M ${x1}, ${y1}`;
const arc1 = `A ${r}, ${r}, 0, ${largerArcFlag1}, 0, ${x2}, ${y2}`;
const arc2 = `A ${r}, ${r}, 0, ${largerArcFlag2}, 0, ${x3}, ${y3}`;
const arcEnd = closedPath ? "Z" : "";
return `${arcStart} ${arc1} ${arc2} ${arcEnd}`;
}

// Overridden in victory-core-native
renderAxisLine(props, style, events) {
const { role, shapeRendering, className } = props;
const path = this.getArcPath(props);
return (
<path className={className}
d={path}
style={style}
role={role || "presentation"}
shapeRendering={shapeRendering || "auto"}
{...events}
/>
);
}

render() {
return this.renderAxisLine(this.props, this.style, this.props.events);
}
}
Loading