diff --git a/demo/ts/app.tsx b/demo/ts/app.tsx index 97bec1bbb..8dcf6cf6f 100644 --- a/demo/ts/app.tsx +++ b/demo/ts/app.tsx @@ -7,10 +7,8 @@ import BrushLineDemo from "./components/victory-brush-line-demo"; import CreateContainerDemo from "./components/create-container-demo"; import CursorContainerDemo from "./components/victory-cursor-container-demo"; import DraggableDemo from "./components/draggable-demo"; -import PolarAxisDemo from "./components/victory-polar-axis-demo"; import SelectionDemo from "./components/selection-demo"; import StackedThemeDemos from "./components/stacked-theme-demo"; -import VictorySelectionContainerDemo from "./components/victory-selection-container-demo"; import VoronoiContainerDemo from "./components/victory-voronoi-container-demo"; import ZoomContainerDemo from "./components/victory-zoom-container-demo"; import ThemeBuilder from "./components/theme-builder"; @@ -35,16 +33,11 @@ const DEMO_ROUTES = { name: "CursorContainerDemo", }, "/demo/draggable": { component: DraggableDemo, name: "DraggableDemo" }, - "/demo/polar-axis": { component: PolarAxisDemo, name: "PolarAxisDemo" }, "/demo/selection": { component: SelectionDemo, name: "SelectionDemo" }, "/demo/stacked-theme": { component: StackedThemeDemos, name: "StackedThemeDemos", }, - "/demo/victory-selection-container": { - component: VictorySelectionContainerDemo, - name: "VictorySelectionContainerDemo", - }, "/demo/voronoi-container": { component: VoronoiContainerDemo, name: "VoronoiContainerDemo", diff --git a/demo/ts/components/victory-polar-axis-demo.tsx b/demo/ts/components/victory-polar-axis-demo.tsx deleted file mode 100644 index 835042361..000000000 --- a/demo/ts/components/victory-polar-axis-demo.tsx +++ /dev/null @@ -1,872 +0,0 @@ -/* eslint no-magic-numbers:0*/ -import React from "react"; -import { VictoryChart } from "victory-chart"; -import { VictoryPolarAxis } from "victory-polar-axis"; -import { VictoryArea } from "victory-area"; -import { VictoryBar } from "victory-bar"; -import { VictoryLine } from "victory-line"; -import { VictoryScatter } from "victory-scatter"; -import { VictoryZoomContainer } from "victory-zoom-container"; -import { VictoryVoronoiContainer } from "victory-voronoi-container"; -import { VictorySelectionContainer } from "victory-selection-container"; -import { VictoryGroup } from "victory-group"; -import { VictoryTooltip } from "victory-tooltip"; -import { VictoryStack } from "victory-stack"; -import { random, range, keys } from "lodash"; -import { VictoryTheme, VictoryLabel, VictoryThemePalette } from "victory-core"; - -type multiAxisDataListType = { - strength?: number; - intelligence?: number; - stealth?: number; -}[]; - -type dataType = { - x?: string | number; - y?: string | number; -}; - -const multiAxisData: multiAxisDataListType = [ - { strength: 1, intelligence: 250, stealth: 45 }, - { strength: 2, intelligence: 300, stealth: 75 }, - { strength: 5, intelligence: 225, stealth: 60 }, -]; - -interface VictoryPolarAxisState { - data: dataType[]; - staticData: dataType[]; - multiAxisData: dataType[][]; - multiAxisMaxima: React.ReactElement[]; -} - -class App extends React.Component { - setStateInterval?: number = undefined; - - constructor(props: any) { - super(props); - - this.state = { - data: this.getData(), - staticData: this.getStaticData(), - multiAxisData: this.processMultiAxisData(multiAxisData), - multiAxisMaxima: this.getMaxData(multiAxisData), - }; - } - - componentDidMount() { - this.setStateInterval = window.setInterval(() => { - this.setState({ - data: this.getData(), - staticData: this.getStaticData(), - }); - }, 3000); - } - - componentWillUnmount() { - window.clearInterval(this.setStateInterval); - } - - getData() { - const points = random(6, 10); - return range(points).map((point: number) => { - const y = random(2, 10); - return { x: point + 1, y }; - }); - } - - getStaticData() { - const points = [10, 20, 30, 40, 50, 60]; - return points.map((point) => { - const y = random(2, 10); - const x = point + random(0, 8); - return { x, y }; - }); - } - - getMaxData(data: multiAxisDataListType) { - const groupedData = keys(data[0]).reduce( - (memo: any, key: string | number) => { - memo[key] = data.map((d) => d[key]); - - return memo; - }, - {}, - ); - - return keys(groupedData).reduce((memo: any, key: string | number) => { - memo[key] = Math.max(...groupedData[key]); - - return memo; - }, {}); - } - - processMultiAxisData(data: multiAxisDataListType) { - const maxByGroup = this.getMaxData(data); - const makeDataArray = (d: any) => { - return keys(d).map((key: string) => { - return { x: key, y: d[key] / maxByGroup[key] }; - }); - }; - - return data.map((datum) => makeDataArray(datum)); - } - - render() { - const containerStyle: React.CSSProperties = { - display: "flex", - flexDirection: "row", - flexWrap: "wrap", - alignItems: "center", - justifyContent: "center", - }; - - const themeColors: VictoryThemePalette = - VictoryTheme.clean.palette?.colors || {}; - - const chartStyle: { [key: string]: React.CSSProperties } = { - parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" }, - }; - - return ( -
-
- - {keys(this.state.multiAxisMaxima).map((key, i) => { - return ( - - } - labelPlacement="perpendicular" - axisValue={i + 1} - label={key} - tickFormat={(t) => t * this.state.multiAxisMaxima[key]} - tickValues={[0.25, 0.5, 0.75]} - /> - ); - })} - ""} /> - - {this.state.multiAxisData.map((data, i) => { - return ; - })} - - - - } - > - - - - datum.y} - labelComponent={} - /> - - - - - `y: ${datum.y}`} - labelComponent={} - /> - - - - - datum.y} - labelComponent={} - /> - - - - - - - - - - - - - } - > - - - - active - ? themeColors.blue || "blue" - : themeColors.red || "red", - }, - }} - labelComponent={} - data={[ - { x: "strength", y: 10, label: "one" }, - { x: "intelligence", y: 25, label: "two" }, - { x: "stealth", y: 40, label: "three" }, - { x: "luck", y: 50, label: "four" }, - { x: "charisma", y: 50, label: "five" }, - ]} - /> - - - - - - - - - { - return [ - { - childName: "bar-2", - mutation: () => { - return { - style: Object.assign({}, props.style, { - fill: themeColors.cyan, - }), - }; - }, - }, - { - childName: "bar-3", - mutation: () => { - return { - style: Object.assign({}, props.style, { - fill: themeColors.blue, - }), - }; - }, - }, - ]; - }, - onMouseOut: () => { - return [ - { - childName: "all", - mutation: () => { - return { style: undefined }; - }, - }, - ]; - }, - }, - }, - ]} - > - ""} - /> - - - - - - - - - { - return [ - { - mutation: () => { - return { - style: Object.assign({}, props.style, { - fill: themeColors.cyan, - }), - }; - }, - }, - ]; - }, - onMouseOut: () => { - return [ - { - mutation: () => { - return { style: undefined }; - }, - }, - ]; - }, - }, - }, - ]} - > - ""} - /> - - - - - - - - - - ""} - /> - - - - - } - > - ""} - /> - - } - labels={({ datum }: any) => `y: ${Math.round(datum.y)}`} - interpolation="linear" - data={this.state.data} - /> - - - - ""} - /> - - - - - - ""} - /> - - - - - } - > - ""} - /> - - themeColors[datum.fill], - }, - }} - data={[ - { x: 45, y: 20, label: 1, fill: "red" }, - { x: 90, y: 30, label: 2, fill: "orange" }, - { x: 135, y: 65, label: 3, fill: "yellow" }, - { x: 250, y: 50, label: 4, fill: "blue" }, - { x: 270, y: 40, label: 5, fill: "cyan" }, - { x: 295, y: 30, label: 6, fill: "green" }, - ]} - /> - - - - - - - themeColors[datum.fill] }, - }} - data={[ - { x: 15, y: 20, label: 1, fill: "red" }, - { x: 25, y: 30, label: 2, fill: "orange" }, - { x: 35, y: 65, label: 3, fill: "yellow" }, - { x: 40, y: 50, label: 4, fill: "blue" }, - { x: 45, y: 40, label: 5, fill: "cyan" }, - { x: 50, y: 30, label: 6, fill: "green" }, - ]} - /> - - - - - - - themeColors[datum.fill] } }} - data={[ - { x: 1, y: 2, label: 1, fill: "red" }, - { x: 2, y: 3, label: 2, fill: "orange" }, - { x: 3, y: 6, label: 3, fill: "yellow" }, - { x: 4, y: 5, label: 4, fill: "blue" }, - { x: 5, y: 4, label: 5, fill: "cyan" }, - { x: 6, y: 3, label: 6, fill: "green" }, - ]} - /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- ); - } -} - -export default App; diff --git a/demo/ts/components/victory-selection-container-demo.tsx b/demo/ts/components/victory-selection-container-demo.tsx deleted file mode 100644 index 8073171f3..000000000 --- a/demo/ts/components/victory-selection-container-demo.tsx +++ /dev/null @@ -1,486 +0,0 @@ -import React from "react"; -import { VictoryArea } from "victory-area"; -import { VictoryBar } from "victory-bar"; -import { VictoryChart } from "victory-chart"; -import { VictoryLine } from "victory-line"; -import { VictoryPolarAxis } from "victory-polar-axis"; -import { VictoryScatter } from "victory-scatter"; -import { VictorySelectionContainer } from "victory-selection-container"; -import { - VictoryTheme, - VictoryLabel, - VictoryStyleInterface, -} from "victory-core"; -import { VictoryVoronoiContainer } from "victory-voronoi-container"; -import { VictoryZoomContainer } from "victory-zoom-container"; -import { random, range, keys } from "lodash"; - -type multiAxisDataListType = { - strength?: number; - intelligence?: number; - stealth?: number; -}[]; - -const multiAxisData: multiAxisDataListType = [ - { strength: 1, intelligence: 250, stealth: 45 }, - { strength: 2, intelligence: 300, stealth: 75 }, - { strength: 5, intelligence: 225, stealth: 60 }, -]; - -const themeColors = VictoryTheme.clean.palette?.colors || {}; -const { - red = "red", - green = "green", - blue = "blue", - cyan = "cyan", - purple = "purple", - orange = "orange", - yellow = "yellow", -} = themeColors; - -class VictorySelectionContainerDemo extends React.Component { - setStateInterval?: number = undefined; - - constructor(props: any) { - super(props); - - this.state = { - data: this.getData(), - staticData: this.getStaticData(), - multiAxisData: this.processMultiAxisData(multiAxisData), - multiAxisMaxima: this.getMaxData(multiAxisData), - }; - } - - componentDidMount() { - this.setStateInterval = window.setInterval(() => { - this.setState({ - data: this.getData(), - staticData: this.getStaticData(), - }); - }, 3000); - } - - componentWillUnmount() { - window.clearInterval(this.setStateInterval); - } - - getData() { - const points = random(6, 10); - return range(points).map((point: number) => { - const y = random(2, 10); - return { x: point + 1, y }; - }); - } - - getStaticData() { - const points = [10, 20, 30, 40, 50, 60]; - return points.map((point) => { - const y = random(2, 10); - const x = point + random(0, 8); - return { x, y }; - }); - } - - getMaxData(data: multiAxisDataListType) { - const groupedData = keys(data[0]).reduce( - (memo: any, key: string | number) => { - memo[key] = data.map((d) => d[key]); - - return memo; - }, - {}, - ); - - return keys(groupedData).reduce((memo: any, key: string | number) => { - memo[key] = Math.max(...groupedData[key]); - - return memo; - }, {}); - } - - processMultiAxisData(data: multiAxisDataListType) { - const maxByGroup = this.getMaxData(data); - const makeDataArray = (d: any) => { - return keys(d).map((key: string) => { - return { x: key, y: d[key] / maxByGroup[key] }; - }); - }; - - return data.map((datum) => makeDataArray(datum)); - } - - render() { - const containerStyle: React.CSSProperties = { - display: "flex", - flexDirection: "row", - flexWrap: "wrap", - alignItems: "center", - justifyContent: "center", - }; - - const chartStyle: VictoryStyleInterface = { - parent: { border: "1px solid #ccc", margin: "2%", maxWidth: "40%" }, - }; - - return ( -
-
- } - > - ""} - /> - - - - - } - > - ""} - /> - - } - labels={({ datum }: any) => `y: ${Math.round(datum.y)}`} - interpolation="linear" - style={{ - data: { stroke: red, strokeWidth: 2 }, - }} - data={this.state.data} - /> - - - - ""} - /> - - - - - - ""} - /> - - - - - } - > - ""} - /> - - datum.fill, opacity: 0.5 }, - }} - data={[ - { x: 45, y: 20, label: 1, fill: red }, - { x: 90, y: 30, label: 2, fill: orange }, - { x: 135, y: 65, label: 3, fill: yellow }, - { x: 250, y: 50, label: 4, fill: blue }, - { x: 270, y: 40, label: 5, fill: cyan }, - { x: 295, y: 30, label: 6, fill: green }, - ]} - /> - - - - - datum.fill, opacity: 0.5 }, - }} - data={[ - { x: 15, y: 20, label: 1, fill: red }, - { x: 25, y: 30, label: 2, fill: orange }, - { x: 35, y: 65, label: 3, fill: yellow }, - { x: 40, y: 50, label: 4, fill: blue }, - { x: 45, y: 40, label: 5, fill: cyan }, - { x: 50, y: 30, label: 6, fill: green }, - ]} - /> - - - - - datum.fill, width: 10 } }} - data={[ - { x: 1, y: 2, label: 1, fill: red }, - { x: 2, y: 3, label: 2, fill: orange }, - { x: 3, y: 6, label: 3, fill: yellow }, - { x: 4, y: 5, label: 4, fill: blue }, - { x: 5, y: 4, label: 5, fill: cyan }, - { x: 6, y: 3, label: 6, fill: green }, - ]} - /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- ); - } -} - -export default VictorySelectionContainerDemo; diff --git a/website/docs/guides/polar-charts.mdx b/website/docs/guides/polar-charts.mdx new file mode 100644 index 000000000..0266e1532 --- /dev/null +++ b/website/docs/guides/polar-charts.mdx @@ -0,0 +1,629 @@ +--- +title: Polar Charts +--- + +Victory supports polar charts for many of its chart types. Polar charts are a type of radial chart, where the data is displayed in a circular graph. + +## Bar Charts + +Bar charts are a common type of polar chart. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a bar series. + +```jsx live + + ""} + /> + + + +``` + +## Bar Charts - Events + +Bar charts can be interactive with the use of events. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a bar series that changes color on hover. + +```jsx live + + } +> + + + + active + ? VictoryTheme.clean.palette + ?.colors.blue || "blue" + : VictoryTheme.clean.palette + ?.colors.red || "red", + }, + }} + labelComponent={} + data={[ + { + x: "strength", + y: 10, + label: "one", + }, + { + x: "intelligence", + y: 25, + label: "two", + }, + { + x: "stealth", + y: 40, + label: "three", + }, + { + x: "luck", + y: 50, + label: "four", + }, + { + x: "charisma", + y: 50, + label: "five", + }, + ]} + /> + +``` + +## Bar Charts - Stacked + +Bar charts can be stacked in a polar format. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a stacked bar series. + +```jsx live + { + return [ + { + childName: "bar-2", + mutation: () => { + return { + style: Object.assign( + {}, + props.style, + { + fill: VictoryTheme + .clean.palette + ?.colors.cyan, + }, + ), + }; + }, + }, + { + childName: "bar-3", + mutation: () => { + return { + style: Object.assign( + {}, + props.style, + { + fill: VictoryTheme + .clean.palette + ?.colors.blue, + }, + ), + }; + }, + }, + ]; + }, + onMouseOut: () => { + return [ + { + childName: "all", + mutation: () => { + return { + style: undefined, + }; + }, + }, + ]; + }, + }, + }, + ]} +> + ""} + /> + + + + + + + +``` + +## Bar & Scatter - Combo + +Bar and Scatter charts are another common combination for polar charts. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a bar and scatter series, and a `VictoryGroup` to apply styles and data to both components. + +```jsx live + + + + + VictoryTheme.clean.palette + ?.colors[datum.fill], + }, + }} + data={[ + { + x: 1, + y: 2, + label: 1, + fill: "red", + }, + { + x: 2, + y: 3, + label: 2, + fill: "orange", + }, + { + x: 3, + y: 6, + label: 3, + fill: "yellow", + }, + { + x: 4, + y: 5, + label: 4, + fill: "blue", + }, + { + x: 5, + y: 4, + label: 5, + fill: "cyan", + }, + { + x: 6, + y: 3, + label: 6, + fill: "green", + }, + ]} + /> + + +``` + +## Line Charts + +Line charts are another common type of polar chart. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a line series. + +```jsx live + + } +> + ""} + /> + + + } + interpolation="linear" + data={[ + { x: 1, y: 2 }, + { x: 2, y: 5 }, + { x: 3, y: 9 }, + { x: 4, y: 6 }, + { x: 5, y: 8 }, + { x: 6, y: 8 }, + { x: 7, y: 2 }, + { x: 8, y: 6 }, + ]} + /> + +``` + +## Line & Scatter Combo + +Line and Scatter charts are a common combination for polar charts. In the following example, we use a `VictoryPolarAxis` to create a polar chart with a line and scatter series, and a `VictoryGroup` to apply styles and data to both components. + +```jsx live + + } +> + + + + datum.y} + labelComponent={ + + } + /> + + + + + + `y: ${datum.y}` + } + labelComponent={ + + } + /> + + + + + datum.y} + labelComponent={ + + } + /> + + +``` + +## Area Charts + +Area charts can also be displayed in a polar format. In the following example, we use a `VictoryPolarAxis` to create a polar chart with an area series. + +```jsx live + + ""} + /> + + + +``` + +## Area Charts - Events + +Area charts can be interactive with the use of events. In the following example, we use a `VictoryPolarAxis` to create a polar chart with an area series that changes color on hover. + +```jsx live + { + return [ + { + mutation: () => { + return { + style: Object.assign( + {}, + props.style, + { + fill: VictoryTheme + .clean.palette + ?.colors.cyan, + }, + ), + }; + }, + }, + ]; + }, + onMouseOut: () => { + return [ + { + mutation: () => { + return { + style: undefined, + }; + }, + }, + ]; + }, + }, + }, + ]} +> + ""} + /> + + + + + + + +``` + +## Area & Scatter Combo + +Area and Scatter charts are another common combination for polar charts. In the following example, we use a `VictoryPolarAxis` to create a polar chart with an area and scatter series, and a `VictoryGroup` to apply styles and data to both components. + +```jsx live + + + + + + +```