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

feat(xo-core): add multi color donut chart ui component #7661

Merged
merged 7 commits into from
Jun 3, 2024

Conversation

P4l0m4
Copy link
Collaborator

@P4l0m4 P4l0m4 commented May 15, 2024

This UI component is an SVG based donut chart.

This is how it looks if all the possible props are provided:
Capture d'écran 2024-05-15 100845

It can receive an array of objects, each containing a value (number) and a color (warning, error, success, unknown).
Example:

{
      value: 15,
      color: 'success',
    },

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.

@P4l0m4 P4l0m4 requested a review from ByScripts May 15, 2024 09:32
@P4l0m4 P4l0m4 self-assigned this May 15, 2024
Copy link
Contributor

@ByScripts ByScripts left a 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>

donut

@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/package.json Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
Copy link
Contributor

@ByScripts ByScripts left a 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.

@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@xen-orchestra/web-core/lib/components/DonutChart.vue Outdated Show resolved Hide resolved
@P4l0m4 P4l0m4 requested a review from ByScripts May 30, 2024 09:07
Copy link
Contributor

@ByScripts ByScripts left a 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.

@pdonias pdonias merged commit 17fec58 into master Jun 3, 2024
1 check passed
@pdonias pdonias deleted the multi-color-donut-chart branch June 3, 2024 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants