Skip to content
Draft
31 changes: 23 additions & 8 deletions packages/api-generator/src/locale/en/VSparkline.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
{
"props": {
"autoDraw": "Trace the length of the line when first rendered.",
"animation": "Enables smooth transitions when values change. When `true`, uses default duration (300ms) and easing (`ease`). Can be an object with `duration` (ms) and `easing` (CSS easing) properties.",
"autoDraw": "Trace the length of the line when first rendered. Since 4.1.0 it accepts `'once'`, to make the animation play only on mount and make the subsequent value changes interpolate smoothly.",
"autoDrawDuration": "Amount of time (in ms) to run the trace animation.",
"autoDrawEasing": "The easing function to use for the trace animation.",
"autoLineWidth": "Automatically expand bars to use space efficiently.",
"fill": "Using the **fill** property allows you to better customize the look and feel of your sparkline.",
"gradient": "An array of colors to use as a linear-gradient.",
"gradientDirection": "The direction the gradient should run.",
"height": "Height of the SVG trendline or bars.",
"height": "Height of the SVG container.",
"id": "The id of the component.",
"inset": "Extends the line beyond the chart boundary so it runs edge-to-edge.",
"interactive": "Enables hover tracking, keyboard navigation (arrow keys), and focus support. Required for **tooltip** to work.",
"itemValue": "The value of the item.",
"labels": "An array of string labels that correspond to the same index as its data counterpart.",
"labelSize": "The label font size.",
"lineWidth": "The thickness of the line, in px.",
"markerSize": "The diameter of marker circles, in px.",
"markerStroke": "The stroke (border) color applied to marker circles.",
"max": "The maximum value of the sparkline.",
"min": "The minimum value of the sparkline.",
"padding": "Low `smooth` or high `line-width` values may result in cropping, increase padding to compensate.",
"showLabels": "Show labels below each data point.",
"smooth": "Number of px to use as a corner radius. `true` defaults to 8, `false` is 0.",
"showMarkers": "Show circle markers at each data point.",
"smooth": "Controls the curve tension. `true` defaults to 8, `false` or `0` gives straight lines. Higher values produce smoother curves.",
"smoothMode": "The interpolation algorithm to use. `default` uses corner-rounding which can cause the line to appear away from actual values. `monotone` makes the line stick to exact data points. In `monotone` mode, **smooth** is limited to 8.",
"tooltip": "Displays a tooltip on the active data point. Requires **interactive**. Can be `true` or an object with `titleFormat`, `offset`, and `showCrosshair` options.",
"type": "Choose between a trendline or bars.",
"width": "Width of the SVG trendline or bars.",
"id": "The id of the component.",
"itemValue": "The value of the item.",
"max": "The maximum value of the sparkline.",
"min": "The minimum value of the sparkline."
"width": "Width of the SVG container."
},
"events": {
"update:currentIndex": "Emitted when the active data point changes via mouse hover, keyboard navigation, or focus. The payload is the point index, or `null` when no point is active."
},
"slots": {
"label": "Custom content for data point labels. Receives `{ index: number, value: string }`.",
"tooltip": "Custom content for the tooltip. Receives `{ index: number, value: number }`."
}
}
16 changes: 16 additions & 0 deletions packages/docs/src/data/new-in.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
"totalVisible": "4.0.0"
}
},
"VSparkline": {
"props": {
"animation": "4.1.0",
"autoDraw": "4.1.0",
"inset": "4.1.0",
"interactive": "4.1.0",
"markerSize": "4.1.0",
"markerStroke": "4.1.0",
"showMarkers": "4.1.0",
"smoothMode": "4.1.0",
"tooltip": "4.1.0"
},
"events": {
"update:currentIndex": "4.1.0"
}
},
"VStepper": {
"props": {
"itemProps": "3.11.0"
Expand Down
103 changes: 103 additions & 0 deletions packages/docs/src/examples/v-sparkline/misc-interactive.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<template>
<v-container>
<v-card class="pa-4 pb-2 mx-auto" rounded="lg" width="500">
<div class="d-flex align-center ga-2 mb-1">
<v-icon icon="mdi-chevron-down" size="18"></v-icon>
<span class="text-uppercase text-body-small font-weight-bold">Weekly Downloads</span>

<v-spacer></v-spacer>

<div class="text-body-small text-medium-emphasis mb-2">
{{ hoveredWeek ?? lastWeek }}
</div>
</div>

<div class="d-flex align-end ga-4 pl-1">
<span class="text-headline-large font-weight-bold mb-1" style="min-width: 140px">
{{ hoveredValue ?? lastValue }}
</span>

<v-sparkline
:gradient="['rgba(var(--v-theme-surface-variant), .2)', 'rgba(var(--v-theme-surface-variant), .1)']"
:model-value="weeklyValues"
class="mr-n2"
color="medium-emphasis"
height="60"
line-width="1.5"
marker-size="12"
marker-stroke="rgb(var(--v-theme-surface))"
min="0"
padding="6"
smooth="2"
stroke-linecap="round"
style="flex: 1"
width="300"
fill
interactive
@update:current-index="hoveredIdx = $event"
></v-sparkline>
</div>
</v-card>
</v-container>
</template>

<script setup>
import { computed, onMounted, ref } from 'vue'
import { useDate } from 'vuetify'

const adapter = useDate()

const weeks = ref([])
const hoveredIdx = ref(null)

const weeklyValues = computed(() => weeks.value.map(w => w.total))

const lastWeek = computed(() => {
const w = weeks.value[weeks.value.length - 1]
return w ? `${w.start} to ${w.end}` : ''
})

const lastValue = computed(() => weeks.value.at(-1)?.total?.toLocaleString())

const hoveredWeek = computed(() => {
if (hoveredIdx.value == null) return null
const w = weeks.value[hoveredIdx.value]
return w ? `${w.start} to ${w.end}` : null
})

const hoveredValue = computed(() => {
if (hoveredIdx.value == null) return null
return weeks.value[hoveredIdx.value]?.total?.toLocaleString()
})

onMounted(async () => {
const today = adapter.date()
const range = [
adapter.startOfWeek(adapter.addMonths(today, -12), 1),
today,
].map(v => adapter.toISO(v)).join(':')

const url = `https://api.npmjs.org/downloads/range/${range}/vuetify`

const res = await fetch(url)
const data = await res.json()

const result = []
const currentWeekday = adapter.toJsDate(today).getDay()
let week = null

for (const d of data.downloads.slice(0, (-currentWeekday))) {
const parsed = adapter.parseISO(d.day)
const isMonday = adapter.isSameDay(parsed, adapter.startOfWeek(parsed, 1))
if (!week || isMonday) {
if (week) result.push(week)
week = { start: d.day, end: d.day, total: 0 }
}
week.end = d.day
week.total += d.downloads
}
if (week) result.push(week)

weeks.value = result
})
</script>
55 changes: 55 additions & 0 deletions packages/docs/src/examples/v-sparkline/prop-animation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<v-card
class="mx-auto pa-4"
max-width="480"
rounded="lg"
>
<div class="d-flex align-center mb-2">
<div>
<div class="text-title-medium font-weight-bold">Page Views</div>
<div class="text-body-small text-medium-emphasis">{{ periodLabel }}</div>
</div>
<v-spacer></v-spacer>
<v-btn-toggle
v-model="period"
density="compact"
rounded="lg"
variant="outlined"
mandatory
>
<v-btn value="weekly">Weekly</v-btn>
<v-btn value="monthly">Monthly</v-btn>
<v-btn value="quarterly">Quarterly</v-btn>
</v-btn-toggle>
</div>

<v-sparkline
:model-value="series[period]"
auto-draw="once"
auto-draw-duration="800"
color="primary"
line-width="2"
smooth="4"
stroke-linecap="round"
animation
></v-sparkline>
</v-card>
</template>

<script setup>
import { computed, ref } from 'vue'

const period = ref('monthly')

const series = {
weekly: [120, 340, 275, 410, 380, 295, 450],
monthly: [640, 820, 550, 910, 770, 1050, 680, 1120, 860, 1240, 930, 1180],
quarterly: [3100, 5800, 4200, 7600, 6100, 3800],
}

const periodLabel = computed(() => ({
weekly: 'Last 7 days',
monthly: 'Last 12 months',
quarterly: 'Last 6 quarters',
})[period.value])
</script>
58 changes: 58 additions & 0 deletions packages/docs/src/examples/v-sparkline/prop-inset.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<v-container>
<v-card
class="pa-5 mx-auto"
color="#0a0a1a"
height="190"
rounded="lg"
width="388"
>
<div class="d-flex align-start mb-2">
<div>
<div class="text-body-medium font-weight-bold text-cyan">Expenses YTD</div>
</div>
<div class="font-weight-bold ml-auto">${{ sum }}</div>
</div>

<v-sparkline
:gradient="['#00e5ff99', '#00e5ff11']"
:model-value="values"
:tooltip="{ class: 'pl-0 bg-grey-darken-4' }"
class="mb-n1"
color="cyan"
height="125"
line-width="1"
marker-size="10"
marker-stroke="#0a0a1a"
min="0"
style="position: absolute; left: 0px; bottom: 0px; height: 125px;"
width="388"
auto-draw
fill
inset
interactive
show-markers
smooth
>
<template v-slot:tooltip="{ index, value }">
<v-list-item density="compact" lines="two">
<template v-slot:prepend>
<v-avatar :color="trend[index] === 'up' ? 'success' : 'warning'" variant="tonal">
<v-icon :icon="trend[index] === 'up' ? 'mdi-arrow-up' : 'mdi-arrow-down'"></v-icon>
</v-avatar>
</template>
<div class="text-body-small">{{ months[index] }}</div>
<div class="text-body-large">${{ value.toLocaleString() }}</div>
</v-list-item>
</template>
</v-sparkline>
</v-card>
</v-container>
</template>

<script setup>
const values = [7600, 5000, 5600, 9800, 2200, 7400, 6640]
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July']
const trend = ['down', 'down', 'up', 'up', 'down', 'up', 'down']
const sum = values.reduce((sum, n) => sum + n, 0).toLocaleString()
</script>
50 changes: 50 additions & 0 deletions packages/docs/src/examples/v-sparkline/prop-smooth-mode.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<v-container>
<v-card class="pa-5 mx-auto" max-width="500" rounded="lg">
<div class="d-flex align-center mb-4">
<v-switch
v-model="monotone"
color="primary"
label="monotone"
hide-details
></v-switch>

<v-spacer></v-spacer>

<v-slider
v-model="smooth"
:max="20"
:min="0"
class="ml-4"
density="compact"
label="smooth"
step="1"
style="max-width: 200px"
hide-details
thumb-label
></v-slider>
</div>

<v-sparkline
:model-value="values"
:smooth="smooth"
:smooth-mode="monotone ? 'monotone' : 'default'"
color="primary"
height="80"
line-width="2"
marker-stroke="rgb(var(--v-theme-surface))"
padding="8"
stroke-linecap="round"
show-markers
></v-sparkline>
</v-card>
</v-container>
</template>

<script setup>
import { shallowRef } from 'vue'

const monotone = shallowRef(true)
const smooth = shallowRef(16)
const values = [0, 10, 10, 3, 3, 0.1, 0, 0.1, 10, 5]
</script>
Loading
Loading