Graph.vue 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <script setup lang="ts">
  2. import { computed, ref, watchEffect } from 'vue'
  3. const props = withDefaults(defineProps<{
  4. points: Array<number> // Array of y-values
  5. value: number
  6. unit: string
  7. label: string
  8. color: string
  9. }>(),
  10. {
  11. points: () => [],
  12. value: 0,
  13. unit: '',
  14. label: '',
  15. color: 'green',
  16. })
  17. const width = 160
  18. const height = 40
  19. const strokeWidth = 2
  20. // Determine the maximum value for scaling the graph
  21. const maxValue = ref(140)
  22. // Update maxValue to accommodate the range of y-values in points
  23. watchEffect(() => {
  24. const highestValue = Math.max(...props.points, 30) // Ensure at least 30
  25. maxValue.value = Math.max(highestValue, maxValue.value)
  26. })
  27. const pointsF = computed(() => props.points.map(
  28. (point, index) =>
  29. `${index * strokeWidth},${height - (point * height / maxValue.value)}`,
  30. ).join(' '))
  31. </script>
  32. <template>
  33. <div
  34. class="
  35. graph
  36. relative
  37. p-1
  38. rounded
  39. text-right
  40. text-xs
  41. outline-none
  42. border-none
  43. font-sans
  44. "
  45. >
  46. <div class="absolute bottom-0.5 right-0.5 font-mono text-xs">
  47. {{ Math.round(value) }} {{ unit }}
  48. </div>
  49. <svg
  50. width="100%"
  51. :height="height"
  52. xmlns="http://www.w3.org/2000/svg"
  53. >
  54. <polyline
  55. :points="pointsF"
  56. fill="none"
  57. :stroke="color"
  58. :stroke-width="strokeWidth"
  59. stroke-linecap="round"
  60. stroke-linejoin="round"
  61. />
  62. </svg>
  63. </div>
  64. </template>
  65. <style>
  66. .graph {
  67. background-color: rgba(var(--nui-c-context), 0.1);
  68. color: rgba(var(--nui-c-context), 1);
  69. }
  70. .graph polyline {
  71. stroke: rgba(var(--nui-c-context), 1);
  72. }
  73. </style>