Circular Bar
Basic Configuration
The Circular Bar chart lays its data records evenly around a circle and draws one petal-shaped bar per record. Each bar grows from the inner edge outward proportionally to its value, and a faded background bar behind it shows the maximum. The minimum configuration looks like:
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
import { VisSingleContainer, VisCircularBar } from '@unovis/react'
function Component(props) {
const data: number[] = props.data
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
return (
<VisSingleContainer data={data}>
<VisCircularBar value={value} maxValue={1} color={color}/>
</VisSingleContainer>
)
}
@Component({
templateUrl: 'template.html'
})
export class Component {
@Input data: number[];
value = (d: number) => d
color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
}
<vis-single-container [data]="data">
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
></vis-circular-bar>
</vis-single-container>
<script lang='ts'>
import { VisSingleContainer, VisCircularBar } from '@unovis/svelte'
export let data: number[]
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
</script>
<VisSingleContainer {data}>
<VisCircularBar {value} maxValue={1} {color}/>
</VisSingleContainer>
<script setup lang="ts">
import { VisSingleContainer, VisCircularBar } from '@unovis/vue'
const props = defineProps<{ data: number[] }>()
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
</script>
<template>
<VisSingleContainer :data="data">
<VisCircularBar :value="value" :maxValue="1" :color="color" />
</VisSingleContainer>
</template>
import { VisSingleContainer, VisCircularBar } from '@unovis/solid'
function Component(props) {
const data: number[] = () => props.data
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
return (
<VisSingleContainer data={data()}>
<VisCircularBar value={value} maxValue={1} color={color}/>
</VisSingleContainer>
)
}
import { SingleContainer, CircularBar } from '@unovis/ts'
import { data } from './data'
const container = new SingleContainer<number>(node, {
component: new CircularBar<number>({
value: (d: number) => d,
maxValue: 1,
color: (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
})
}, data)
Max Value
A bar with value === maxValue reaches the outer radius of the chart. When maxValue is undefined (the default),
the maximum is derived from the data. Pass a number to use one max for all bars, a per-datum accessor when each bar
should scale against its own target, or an array indexed by the datum's position in data:
// Auto-derive max from data (default)
maxValue={undefined}
// Single shared max
maxValue={100}
// Per-bar target
maxValue={d => d.target}
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar value={value} maxValue={maxValue} color={color}/>
<vis-circular-bar
[value]="value"
[maxValue]="maxValue"
[color]="color"
></vis-circular-bar>
<VisCircularBar {value} {maxValue} {color}/>
<VisCircularBar :value="value" :maxValue="maxValue" :color="color" />
<VisCircularBar value={value} maxValue={maxValue} color={color}/>
const circularBar = new CircularBar<number>({ value, maxValue, color })
Bar Shape
The bars get their petal-like look from four properties, all in pixels. By default they are derived from the chart radius (inner radius 26%, outer corners 12%, gap 3%, and inner corners large enough to merge into a single rounded tip), so the proportions hold at any size. The corner radii are reduced automatically when a bar is too short or too narrow to fit them.
Inner Radius
innerRadius is the radius of the hole in the middle of the chart. Bars start at the inner radius (unless barPadding
and innerCornerRadius force them to start farther away from the center), and by default their inner corners merge
into a single rounded tip touching it. Set it to 0 to make the tips converge towards the center.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
innerRadius={40}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[innerRadius]="40"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} innerRadius={40}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:innerRadius="40"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
innerRadius={40}
/>
const circularBar = new CircularBar<number>({ value, maxValue: 1, color, innerRadius: 40 })
Bar Padding
barPadding is the gap between neighbouring bars. Unlike an angular padding, the gap has the same width along
the whole side of a bar, so the sides of neighbouring bars stay parallel.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
barPadding={16}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[barPadding]="16"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} barPadding={16}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:barPadding="16"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
barPadding={16}
/>
const circularBar = new CircularBar<number>({ value, maxValue: 1, color, barPadding: 16 })
Corner Radius
cornerRadius rounds the two outer corners of a bar.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
cornerRadius={40}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[cornerRadius]="40"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} cornerRadius={40}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:cornerRadius="40"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
cornerRadius={40}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
cornerRadius: 40
})
Inner Corner Radius
innerCornerRadius rounds the two inner corners of a bar. By default it is large enough for the two corners to merge
into a single rounded tip touching the inner radius, with a rounding of at least a fraction of the bar's width (so
very narrow bars or a small inner radius start slightly beyond it). Smaller values leave a piece of the inner circle
between the corners, larger values move the tip away from the center. Bars too wide for a tip, e.g. three bars over the
full circle, keep two rounded corners and a short inner arc.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
innerCornerRadius={10}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[innerCornerRadius]="10"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} innerCornerRadius={10}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:innerCornerRadius="10"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
innerCornerRadius={10}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
innerCornerRadius: 10
})
Angle Range
By default the bars cover the full circle and the first bar is centered at the top. Pass a [start, end] tuple in
radians to render a partial range or to rotate the chart. The bars are distributed evenly within it, and the first one
starts at start. At 180° and more (i.e. one or two bars over the full circle) the padded sides of a bar never meet,
so such bars are drawn as regular arcs instead of petals, with cornerRadius rounding all four corners
(innerCornerRadius doesn't apply to them).
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
angleRange={[-1.5707963267948966,1.5707963267948966]}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[angleRange]="[-1.5707963267948966,1.5707963267948966]"
></vis-circular-bar>
<VisCircularBar
{value}
maxValue={1}
{color}
angleRange={[-1.5707963267948966,1.5707963267948966]}
/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:angleRange="[-1.5707963267948966,1.5707963267948966]"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
angleRange={[-1.5707963267948966,1.5707963267948966]}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
angleRange: [-1.5707963267948966,1.5707963267948966]
})
Minimum Bar Length
Bars representing very small values can become too small to notice. barMinLength sets the minimum length of a bar
in pixels, measured from its inner edge to its outer edge, so that such bars remain visible. It defaults to 0.
0 counts as a value, so zero bars are extended to the minimum length too. Missing data is different: when the
value accessor returns null or undefined, the bar is not rendered at all and only its background remains.
In the example below the bars are, clockwise from the top: a regular value, a tiny value, 0, null and another regular value:
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
barMinLength={20}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[barMinLength]="20"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} barMinLength={20}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:barMinLength="20"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
barMinLength={20}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
barMinLength: 20
})
Sorting
Provide a sortFunction to control the bar order independently of how the data was provided:
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
sortFunction={sortFunction}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[sortFunction]="sortFunction"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} {sortFunction}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:sortFunction="sortFunction"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
sortFunction={sortFunction}
/>
const circularBar = new CircularBar<number>({ value, maxValue: 1, color, sortFunction })
Radius
radius sets the outer radius of the chart in pixels. When undefined, the chart fills the available space.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar value={value} maxValue={1} color={color} radius={100}/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[radius]="100"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} radius={100}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:radius="100"
/>
<VisCircularBar value={value} maxValue={1} color={color} radius={100}/>
const circularBar = new CircularBar<number>({ value, maxValue: 1, color, radius: 100 })
Custom Color
Customize the colors with a color accessor:
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
function Component(props) {
const data: number[] = props.data
const value = (d: number) => d
const color = (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
return (
<VisCircularBar value={value} maxValue={1} color={color}/>
)
}
@Component({
template: `
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
></vis-circular-bar>
`
})
export class Component {
@Input data: number[];
value = (d: number) => d
color = (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
}
<script lang='ts'>
import { VisSingleContainer, VisCircularBar } from '@unovis/svelte'
export let data: number[]
const value = (d: number) => d
const color = (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
</script>
<VisCircularBar {value} maxValue={1} {color}/>
<script setup lang="ts">
import { VisSingleContainer, VisCircularBar } from '@unovis/vue'
const props = defineProps<{ data: number[] }>()
const value = (d: number) => d
const color = (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
</script>
<template>
<VisCircularBar :value="value" :maxValue="1" :color="color" />
</template>
function Component(props) {
const data: number[] = () => props.data
const value = (d: number) => d
const color = (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
return (
<VisCircularBar value={value} maxValue={1} color={color}/>
)
}
const circularBar = new CircularBar<number>({
value: (d: number) => d,
maxValue: 1,
color: (d: number, i: number) => ['#2FB8B0', '#57B24A', '#FF6A2B', '#FF3B5C', '#A53CF0', '#7A5CFF', '#1F7CFF'][i]
})
Icons
Use icon to display a small icon at the inner end of each bar. The icon is hidden when its bar is too short to fit it.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
import { VisSingleContainer, VisCircularBar } from '@unovis/react'
function Component(props) {
const data: number[] = props.data
const svgDefs = `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
const icon = (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i]
return (
<VisSingleContainer
svgDefs={svgDefs}
data={data}
>
<VisCircularBar
value={value}
maxValue={1}
color={color}
icon={icon}
iconSize={18}
/>
</VisSingleContainer>
)
}
@Component({
templateUrl: 'template.html'
})
export class Component {
@Input data: number[];
svgDefs = `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`
value = (d: number) => d
color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
icon = (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i]
}
<vis-single-container
[svgDefs]="svgDefs"
[data]="data"
>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[icon]="icon"
[iconSize]="18"
></vis-circular-bar>
</vis-single-container>
<script lang='ts'>
import { VisSingleContainer, VisCircularBar } from '@unovis/svelte'
export let data: number[]
const svgDefs = `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
const icon = (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i]
</script>
<VisSingleContainer {svgDefs} {data}>
<VisCircularBar {value} maxValue={1} {color} {icon} iconSize={18}/>
</VisSingleContainer>
<script setup lang="ts">
import { VisSingleContainer, VisCircularBar } from '@unovis/vue'
const props = defineProps<{ data: number[] }>()
const svgDefs = `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
const icon = (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i]
</script>
<template>
<VisSingleContainer
:svgDefs="svgDefs"
:data="data"
>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:icon="icon"
:iconSize="18"
/>
</VisSingleContainer>
</template>
import { VisSingleContainer, VisCircularBar } from '@unovis/solid'
function Component(props) {
const data: number[] = () => props.data
const svgDefs = `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`
const value = (d: number) => d
const color = (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7]
const icon = (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i]
return (
<VisSingleContainer
svgDefs={svgDefs}
data={data()}
>
<VisCircularBar
value={value}
maxValue={1}
color={color}
icon={icon}
iconSize={18}
/>
</VisSingleContainer>
)
}
import { SingleContainer, CircularBar } from '@unovis/ts'
import { data } from './data'
const container = new SingleContainer<number>(node, {
svgDefs: `<symbol id="heart" viewBox="0 0 24 24">...</symbol> ...`,
component: new CircularBar<number>({
value: (d: number) => d,
maxValue: 1,
color: (d: number, i: number) => ['var(--vis-color0)', 'var(--vis-color1)', 'var(--vis-color2)', 'var(--vis-color3)', 'var(--vis-color4)', 'var(--vis-color5)', '#57BAFF'][i % 7],
icon: (d: number, i: number) => ['#heart', '#sun', '#drop', '#bolt', '#moon', '#star', '#leaf'][i],
iconSize: 18
})
}, data)
icon accepts either a href to an SVG symbol defined in the container's svgDefs, like in the example above, or text: an
icon font glyph (e.g. '' for Font Awesome's heart, with the font set via the --vis-circular-bar-icon-font-family
and --vis-circular-bar-icon-font-weight CSS variables) or a Unicode symbol. SVG icons are filled with the
--vis-circular-bar-icon-color CSS variable, which is also available as currentColor for strokes. Icons don't capture
pointer events, so hovering them triggers the events of the bar underneath (e.g. its tooltip).
Icon Size
iconSize sets the size of the icons in pixels. When undefined, it's 8% of the chart radius.
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
icon={icon}
iconSize={18}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[icon]="icon"
[iconSize]="18"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} {icon} iconSize={18}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:icon="icon"
:iconSize="18"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
icon={icon}
iconSize={18}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
icon,
iconSize: 18
})
Background
By default each bar has a faded background of the maximum length behind it. Disable it with showBackground={false}:
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
showBackground={true}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[showBackground]="true"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} showBackground={true}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:showBackground="true"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
showBackground={true}
/>
const circularBar = new CircularBar<number>({
value,
maxValue: 1,
color,
showBackground: true
})
The background color is configured via the --vis-circular-bar-background-color and
--vis-dark-circular-bar-background-color CSS variables.
Events
The following selectors are available for events:
import { CircularBar } from '@unovis/ts'
...
events = {
[CircularBar.selectors.bar]: { },
[CircularBar.selectors.background]: { },
}
- React
- Angular
- Svelte
- Vue
- Solid
- TypeScript
<VisCircularBar
value={value}
maxValue={1}
color={color}
events={events}
/>
<vis-circular-bar
[value]="value"
[maxValue]="1"
[color]="color"
[events]="events"
></vis-circular-bar>
<VisCircularBar {value} maxValue={1} {color} {events}/>
<VisCircularBar
:value="value"
:maxValue="1"
:color="color"
:events="events"
/>
<VisCircularBar
value={value}
maxValue={1}
color={color}
events={events}
/>
const circularBar = new CircularBar<number>({ value, maxValue: 1, color, events })
CSS Variables
All supported CSS variables and their default values
--vis-circular-bar-background-color: #E7E9F3;
--vis-circular-bar-bar-stroke-width: 0;
--vis-circular-bar-bar-stroke-color: undefined;
--vis-circular-bar-icon-color: rgba(255, 255, 255, 0.9);
--vis-circular-bar-icon-font-family: undefined;
--vis-circular-bar-icon-font-weight: normal;
--vis-dark-circular-bar-background-color: #444444;
--vis-dark-circular-bar-icon-color: rgba(255, 255, 255, 0.9);
Component Props
| Name | Type | Description |
|---|---|---|
| * required property |