-
Notifications
You must be signed in to change notification settings - Fork 254
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
feat(xo-core): add multi color donut chart ui component #7661
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to my comments, here is a POC for an SVG-based donut chart (not battle tested and some parts might be missing, but should be a good starting point).
<template>
<svg class="donut-chart" viewBox="0 0 100 100">
<circle class="segment" cx="50" cy="50" r="40" />
<circle
v-for="segment of segments"
:key="segment.label"
:class="segment.color"
:stroke-dasharray="`${segment.percent} ${CIRCUMFERENCE - segment.percent}`"
:stroke-dashoffset="segment.offset"
class="segment"
cx="50"
cy="50"
r="40"
/>
<UiIcon :icon height="24" width="24" x="38" y="38" />
</svg>
</template>
<script lang="ts" setup>
import UiIcon from '@core/components/icon/UiIcon.vue'
import type { Color } from '@core/types/color.type'
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
import { computed } from 'vue'
type SegmentConfiguration = {
label: string
value: number
color: Color | undefined
}
type Segment = {
label: string
color: Color | undefined
percent: number
offset: number
}
const props = defineProps<{
segments: SegmentConfiguration[]
icon?: IconDefinition
max?: number
}>()
const CIRCUMFERENCE = Math.PI * 80
const maxValue = computed(() => props.max ?? props.segments.reduce((acc, segment) => acc + segment.value, 0))
const segments = computed<Segment[]>(() => {
let nextOffset = CIRCUMFERENCE / 4
return props.segments.map(segment => {
const offset = nextOffset
const percent = (segment.value / maxValue.value) * CIRCUMFERENCE
nextOffset -= percent
return {
label: segment.label,
color: segment.color,
percent,
offset,
}
})
})
</script>
<style scoped>
.donut-chart {
width: 10rem;
height: 10rem;
}
.segment {
stroke: var(--color-grey-400);
stroke-width: 10;
fill: transparent;
}
.info {
stroke: var(--color-purple-base);
}
.success {
stroke: var(--color-green-base);
}
.warning {
stroke: var(--color-orange-base);
}
.error, .danger {
stroke: var(--color-red-base);
}
</style>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, I asked Clémence about the grey-100
segments, which doesn't seems clear to me on the DS.
… and shorter js calculations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pdonias Can you merge? Thanks.
This UI component is an SVG based donut chart.
This is how it looks if all the possible props are provided:
It can receive an array of objects, each containing a value (number) and a color (warning, error, success, unknown).
Example:
It can also receive an icon prop (icon must be of IconDefinition type) and a max value that, if greater than the sum of the segment's value, will add an extra segment with a default color.