nuxt-charts 3.0.0-beta.0 → 3.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +2 -2
- package/dist/runtime/assets/components.css +1 -1
- package/dist/runtime/assets/theme.css +1 -1
- package/dist/runtime/components/BubbleChart.vue +3 -3
- package/dist/runtime/components/DonutChart.vue +4 -3
- package/dist/runtime/components/FunnelChart.vue +5 -5
- package/dist/runtime/components/RadarChart.vue +3 -3
- package/dist/runtime/components/RadialBarChart.vue +3 -3
- package/dist/runtime/components/internal/CartesianFrame.vue +3 -3
- package/dist/runtime/components/internal/ChartContainer.d.ts +91 -0
- package/dist/runtime/components/internal/ChartContainer.js +111 -0
- package/dist/runtime/components/internal/FunnelLayeredShape.vue +6 -6
- package/package.json +21 -18
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer vue-chrts{.vc-tooltip{background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));font-size:var(--vc-legend-size,.75rem);line-height:1.5;min-width:8rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none}.vc-tooltip,.vc-tooltip__label{color:var(--vc-tooltip-fg,oklch(.205 0 0))}.vc-tooltip__label{font-weight:500;margin:0 0 .25rem}.vc-tooltip__list{display:flex;flex-direction:column;gap:.125rem;list-style:none;margin:0;padding:0}.vc-tooltip__item{align-items:center;display:flex;gap:.375rem}.vc-tooltip__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:.5rem;width:.5rem}.vc-tooltip__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-tooltip__value{color:var(--vc-tooltip-fg,oklch(.205 0 0));font-variant-numeric:tabular-nums;font-weight:500;margin-left:auto}.vc-legend{flex-wrap:wrap;font-size:var(--vc-legend-size,.75rem);font-weight:var(--vc-legend-weight,400);gap:var(--vc-legend-gap,.75rem);justify-content:center;line-height:1.5;list-style:none;margin:0;padding:0}.vc-legend,.vc-legend__item{align-items:center;display:flex}.vc-legend__item{gap:.375rem}.vc-legend__item--inactive{opacity:.4}.vc-legend__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-legend__label{color:var(--vc-legend-color,oklch(.556 0 0))}.vc-candlestick-chart{cursor:crosshair;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.vc-candlestick-chart__svg{display:block;overflow:visible;width:100%}.vc-funnel-layered{position:relative;width:100%}.vc-funnel-layered__tooltip{align-items:center;background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));color:var(--vc-tooltip-fg,oklch(.205 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);gap:.375rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none;position:absolute;transform:translate(-50%,calc(-100% - 10px));white-space:nowrap}.vc-funnel-layered__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-funnel-layered__value{font-variant-numeric:tabular-nums;font-weight:600}.vc-funnel-layered__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-funnel-layered-shape{opacity:.96;transition:opacity .15s}.vc-funnel-layered-shape:hover{opacity:1}.vc-status-tracker{color:var(--foreground,oklch(.205 0 0));font-family:inherit;width:100%}.vc-status-tracker__header{align-items:baseline;display:flex;gap:1rem;justify-content:space-between;margin-bottom:.75rem}.vc-status-tracker__summary,.vc-status-tracker__title{font-size:.875rem;line-height:1.25rem;margin:0}.vc-status-tracker__title{font-weight:600}.vc-status-tracker__summary{color:var(--muted-foreground,oklch(.556 0 0));font-variant-numeric:tabular-nums}.vc-status-tracker__track{display:flex;overflow:hidden;width:100%}.vc-status-tracker__bar{display:block;flex:0 0 auto;height:100%;min-width:1px;transition:opacity .16s ease}.vc-status-tracker__bar:hover{opacity:.78}.vc-status-tracker__bar--rounded-start{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.vc-status-tracker__bar--rounded-end{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.vc-status-tracker__bar--empty:hover{opacity:1}.vc-status-tracker__labels{gap:1rem;justify-content:space-between;margin-top:.5rem}.vc-status-tracker__labels,.vc-status-tracker__legend{color:var(--vc-legend-color,oklch(.556 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);line-height:1rem}.vc-status-tracker__legend{flex-wrap:wrap;gap:.5rem 1rem;list-style:none;margin:.75rem 0 0;padding:0}.vc-status-tracker__legend-item{align-items:center;display:inline-flex;gap:.375rem}.vc-status-tracker__legend-dot{border-radius:9999px;flex:0 0 auto;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}}
|
|
1
|
+
@layer vue-chrts{.vc-tooltip{background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));font-size:var(--vc-legend-size,.75rem);line-height:1.5;min-width:8rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none}.vc-tooltip,.vc-tooltip__label{color:var(--vc-tooltip-fg,oklch(.205 0 0))}.vc-tooltip__label{font-weight:500;margin:0 0 .25rem}.vc-tooltip__list{display:flex;flex-direction:column;gap:.125rem;list-style:none;margin:0;padding:0}.vc-tooltip__item{align-items:center;display:flex;gap:.375rem}.vc-tooltip__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:.5rem;width:.5rem}.vc-tooltip__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-tooltip__value{color:var(--vc-tooltip-fg,oklch(.205 0 0));font-variant-numeric:tabular-nums;font-weight:500;margin-left:auto}.vc-legend{flex-wrap:wrap;font-size:var(--vc-legend-size,.75rem);font-weight:var(--vc-legend-weight,400);gap:var(--vc-legend-gap,.75rem);justify-content:center;line-height:1.5;list-style:none;margin:0;padding:0}.vc-legend,.vc-legend__item{align-items:center;display:flex}.vc-legend__item{gap:.375rem}.vc-legend__item--inactive{opacity:.4}.vc-legend__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-legend__label{color:var(--vc-legend-color,oklch(.556 0 0))}.vc-candlestick-chart{cursor:crosshair;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.vc-candlestick-chart__svg{display:block;overflow:visible;width:100%}.vc-funnel-layered{position:relative;width:100%}.vc-funnel-layered__tooltip{align-items:center;background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));color:var(--vc-tooltip-fg,oklch(.205 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);gap:.375rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none;position:absolute;transform:translate(-50%,calc(-100% - 10px));white-space:nowrap}.vc-funnel-layered__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-funnel-layered__value{font-variant-numeric:tabular-nums;font-weight:600}.vc-funnel-layered__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-funnel-layered-shape{opacity:.96;transition:opacity .15s}.vc-funnel-layered-shape:hover{opacity:1}.vc-status-tracker{color:var(--vc-axis-label-color,var(--ui-text-highlighted,var(--foreground,oklch(.205 0 0))));font-family:inherit;width:100%}.vc-status-tracker__header{align-items:baseline;display:flex;gap:1rem;justify-content:space-between;margin-bottom:.75rem}.vc-status-tracker__summary,.vc-status-tracker__title{font-size:.875rem;line-height:1.25rem;margin:0}.vc-status-tracker__title{font-weight:600}.vc-status-tracker__summary{color:var(--vc-tick-color,var(--ui-text-muted,var(--muted-foreground,oklch(.556 0 0))));font-variant-numeric:tabular-nums}.vc-status-tracker__track{display:flex;overflow:hidden;width:100%}.vc-status-tracker__bar{display:block;flex:0 0 auto;height:100%;min-width:1px;transition:opacity .16s ease}.vc-status-tracker__bar:hover{opacity:.78}.vc-status-tracker__bar--rounded-start{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.vc-status-tracker__bar--rounded-end{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.vc-status-tracker__bar--empty:hover{opacity:1}.vc-status-tracker__labels{gap:1rem;justify-content:space-between;margin-top:.5rem}.vc-status-tracker__labels,.vc-status-tracker__legend{color:var(--vc-legend-color,oklch(.556 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);line-height:1rem}.vc-status-tracker__legend{flex-wrap:wrap;gap:.5rem 1rem;list-style:none;margin:.75rem 0 0;padding:0}.vc-status-tracker__legend-item{align-items:center;display:inline-flex;gap:.375rem}.vc-status-tracker__legend-dot{border-radius:9999px;flex:0 0 auto;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer vue-chrts{.vue-chrts{--vc-grid-color:var(--border,oklch(0.922 0 0));--vc-grid-dash:3 3;--vc-grid-width:1px;--vc-axis-line-color:var(--border,oklch(0.922 0 0));--vc-axis-line-width:1px;--vc-legend-size:0.75rem;--vc-legend-weight:400;--vc-tick-color:var(--muted-foreground,oklch(0.556 0 0));--vc-tick-size:var(--vc-legend-size);--vc-tick-weight:var(--vc-legend-weight);--vc-axis-label-color:var(--foreground,oklch(0.205 0 0));--vc-axis-label-size:var(--vc-legend-size);--vc-axis-label-weight:500}.vue-chrts .v-charts-cartesian-axis .v-charts-label{fill:var(--vc-axis-label-color);font-size:var(--vc-axis-label-size);font-weight:var(--vc-axis-label-weight)}.vue-chrts{--vc-legend-gap:0.75rem;--vc-legend-inset:0.75rem;--vc-legend-color:var(--muted-foreground,oklch(0.556 0 0));--vc-legend-dot-size:0.5rem;--vc-hover-fill:color-mix(in oklab,var(--foreground,oklch(0.205 0 0)) 6%,transparent);--vc-hover-stroke:transparent;--vc-hover-radius:6px;--vc-tooltip-bg:var(--popover,oklch(1 0 0));--vc-tooltip-fg:var(--popover-foreground,oklch(0.205 0 0));--vc-tooltip-muted:var(--muted-foreground,oklch(0.556 0 0));--vc-tooltip-border:var(--border,oklch(0.922 0 0));--vc-tooltip-radius:0.5rem;--vc-tooltip-padding:0.375rem 0.625rem;--vc-tooltip-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.vue-chrts .v-charts-xAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-x-tick-color,var(--vc-tick-color));font-size:var(--vc-x-tick-size,var(--vc-tick-size));font-weight:var(--vc-x-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-yAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-y-tick-color,var(--vc-tick-color));font-size:var(--vc-y-tick-size,var(--vc-tick-size));font-weight:var(--vc-y-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-polar-angle-axis-tick-value,.vue-chrts .v-charts-polar-radius-axis-tick-value{fill:var(--vc-tick-color);font-size:var(--vc-tick-size);font-weight:var(--vc-tick-weight)}.vue-chrts:is(.dark,[data-theme=dark],.dark *,[data-theme=dark] *),:is(.dark,[data-theme=dark]) .vue-chrts{--vc-grid-color:var(--border,oklch(0.269 0 0));--vc-axis-line-color:var(--border,oklch(0.269 0 0));--vc-tick-color:var(--muted-foreground,oklch(0.708 0 0));--vc-axis-label-color:var(--foreground,oklch(0.985 0 0));--vc-legend-color:var(--muted-foreground,oklch(0.708 0 0));--vc-hover-fill:color-mix(in oklab,oklch(0.985 0 0) 8%,transparent);--vc-tooltip-bg:var(--popover,oklch(0.205 0 0));--vc-tooltip-fg:var(--popover-foreground,oklch(0.985 0 0));--vc-tooltip-muted:var(--muted-foreground,oklch(0.708 0 0));--vc-tooltip-border:var(--border,oklch(0.269 0 0))}}
|
|
1
|
+
@layer vue-chrts{.vue-chrts{--vc-grid-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-grid-dash:3 3;--vc-grid-width:1px;--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-axis-line-width:1px;--vc-surface-bg:var(--ui-bg,var(--background,oklch(1 0 0)));--vc-legend-size:0.75rem;--vc-legend-weight:400;--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tick-size:var(--vc-legend-size);--vc-tick-weight:var(--vc-legend-weight);--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0)));--vc-axis-label-size:var(--vc-legend-size);--vc-axis-label-weight:500}.vue-chrts .v-charts-cartesian-axis .v-charts-label{fill:var(--vc-axis-label-color);font-size:var(--vc-axis-label-size);font-weight:var(--vc-axis-label-weight)}.vue-chrts{--vc-legend-gap:0.75rem;--vc-legend-inset:0.75rem;--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-legend-dot-size:0.5rem;--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0))) 6%,transparent);--vc-hover-stroke:transparent;--vc-hover-radius:6px;--vc-tooltip-bg:var(--ui-bg,var(--popover,oklch(1 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.205 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-tooltip-radius:0.5rem;--vc-tooltip-padding:0.375rem 0.625rem;--vc-tooltip-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.vue-chrts .v-charts-xAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-x-tick-color,var(--vc-tick-color));font-size:var(--vc-x-tick-size,var(--vc-tick-size));font-weight:var(--vc-x-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-yAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-y-tick-color,var(--vc-tick-color));font-size:var(--vc-y-tick-size,var(--vc-tick-size));font-weight:var(--vc-y-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-polar-angle-axis-tick-value,.vue-chrts .v-charts-polar-radius-axis-tick-value{fill:var(--vc-tick-color);font-size:var(--vc-tick-size);font-weight:var(--vc-tick-weight)}.vue-chrts:is(.dark,[data-theme=dark],.dark *,[data-theme=dark] *),:is(.dark,[data-theme=dark]) .vue-chrts{--vc-grid-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-surface-bg:var(--ui-bg,var(--background,oklch(0.145 0 0)));--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.985 0 0)));--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,oklch(0.985 0 0)) 8%,transparent);--vc-tooltip-bg:var(--ui-bg,var(--popover,oklch(0.205 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.985 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.269 0 0)))}}
|
|
@@ -3,7 +3,6 @@ import { computed } from "vue";
|
|
|
3
3
|
import {
|
|
4
4
|
CartesianGrid,
|
|
5
5
|
Legend,
|
|
6
|
-
ResponsiveContainer,
|
|
7
6
|
Scatter,
|
|
8
7
|
ScatterChart,
|
|
9
8
|
Tooltip,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
YAxis,
|
|
12
11
|
ZAxis
|
|
13
12
|
} from "vccs";
|
|
13
|
+
import ChartContainer from "./internal/ChartContainer";
|
|
14
14
|
import ChartTooltip from "./internal/ChartTooltip.vue";
|
|
15
15
|
import ChartLegend from "./internal/ChartLegend.vue";
|
|
16
16
|
import { categoriesToSeries } from "../utils/categories";
|
|
@@ -147,7 +147,7 @@ const groups = computed(() => {
|
|
|
147
147
|
|
|
148
148
|
<template>
|
|
149
149
|
<div class="vue-chrts" :style="themeVars">
|
|
150
|
-
<
|
|
150
|
+
<ChartContainer width="100%" :height="height">
|
|
151
151
|
<ScatterChart>
|
|
152
152
|
<CartesianGrid
|
|
153
153
|
v-if="(xGridLine ?? true) || (yGridLine ?? true)"
|
|
@@ -208,6 +208,6 @@ const groups = computed(() => {
|
|
|
208
208
|
</template>
|
|
209
209
|
</Legend>
|
|
210
210
|
</ScatterChart>
|
|
211
|
-
</
|
|
211
|
+
</ChartContainer>
|
|
212
212
|
</div>
|
|
213
213
|
</template>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
-
import { Legend, Pie, PieChart,
|
|
3
|
+
import { Legend, Pie, PieChart, Tooltip } from "vccs";
|
|
4
|
+
import ChartContainer from "./internal/ChartContainer";
|
|
4
5
|
import ChartTooltip from "./internal/ChartTooltip.vue";
|
|
5
6
|
import ChartLegend from "./internal/ChartLegend.vue";
|
|
6
7
|
import { DonutType } from "../enums";
|
|
@@ -69,7 +70,7 @@ const legendWrapperStyle = computed(
|
|
|
69
70
|
|
|
70
71
|
<template>
|
|
71
72
|
<div class="donut-chart vue-chrts" :style="{ position: 'relative', width: '100%', height: `${height ?? (radius ? radius * 2 : 200)}px`, ...themeVars }">
|
|
72
|
-
<
|
|
73
|
+
<ChartContainer width="100%" height="100%">
|
|
73
74
|
<PieChart>
|
|
74
75
|
<Pie
|
|
75
76
|
:data="segments"
|
|
@@ -96,7 +97,7 @@ const legendWrapperStyle = computed(
|
|
|
96
97
|
</template>
|
|
97
98
|
</Legend>
|
|
98
99
|
</PieChart>
|
|
99
|
-
</
|
|
100
|
+
</ChartContainer>
|
|
100
101
|
|
|
101
102
|
<!-- Centered overlay for custom content (v2 parity: default slot). -->
|
|
102
103
|
<div
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
FunnelChart as VccsFunnelChart,
|
|
6
6
|
LabelList,
|
|
7
7
|
Legend,
|
|
8
|
-
ResponsiveContainer,
|
|
9
8
|
Tooltip
|
|
10
9
|
} from "vccs";
|
|
10
|
+
import ChartContainer from "./internal/ChartContainer";
|
|
11
11
|
import ChartTooltip from "./internal/ChartTooltip.vue";
|
|
12
12
|
import ChartLegend from "./internal/ChartLegend.vue";
|
|
13
13
|
import FunnelLayeredShape, {
|
|
@@ -85,7 +85,7 @@ function hideTooltip() {
|
|
|
85
85
|
class="vc-funnel-layered vue-chrts"
|
|
86
86
|
:style="{ height: `${height}px`, ...themeVars }"
|
|
87
87
|
>
|
|
88
|
-
<
|
|
88
|
+
<ChartContainer width="100%" height="100%">
|
|
89
89
|
<VccsFunnelChart :margin="{ top: 16, right: 0, bottom: 8, left: 0 }">
|
|
90
90
|
<Funnel
|
|
91
91
|
:data="layeredData"
|
|
@@ -104,7 +104,7 @@ function hideTooltip() {
|
|
|
104
104
|
</template>
|
|
105
105
|
</Funnel>
|
|
106
106
|
</VccsFunnelChart>
|
|
107
|
-
</
|
|
107
|
+
</ChartContainer>
|
|
108
108
|
|
|
109
109
|
<div
|
|
110
110
|
v-if="!hideTooltip && activeDatum"
|
|
@@ -123,7 +123,7 @@ function hideTooltip() {
|
|
|
123
123
|
</div>
|
|
124
124
|
|
|
125
125
|
<div v-else class="vue-chrts" :style="themeVars">
|
|
126
|
-
<
|
|
126
|
+
<ChartContainer width="100%" :height="height">
|
|
127
127
|
<VccsFunnelChart>
|
|
128
128
|
<Funnel
|
|
129
129
|
:data="stages"
|
|
@@ -147,6 +147,6 @@ function hideTooltip() {
|
|
|
147
147
|
</template>
|
|
148
148
|
</Legend>
|
|
149
149
|
</VccsFunnelChart>
|
|
150
|
-
</
|
|
150
|
+
</ChartContainer>
|
|
151
151
|
</div>
|
|
152
152
|
</template>
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
PolarRadiusAxis,
|
|
8
8
|
Radar,
|
|
9
9
|
RadarChart as VccsRadarChart,
|
|
10
|
-
ResponsiveContainer,
|
|
11
10
|
Tooltip
|
|
12
11
|
} from "vccs";
|
|
12
|
+
import ChartContainer from "./internal/ChartContainer";
|
|
13
13
|
import ChartTooltip from "./internal/ChartTooltip.vue";
|
|
14
14
|
import ChartLegend from "./internal/ChartLegend.vue";
|
|
15
15
|
import { categoriesToSeries } from "../utils/categories";
|
|
@@ -45,7 +45,7 @@ const themeVars = computed(() => themeToVars(props.theme));
|
|
|
45
45
|
|
|
46
46
|
<template>
|
|
47
47
|
<div class="vue-chrts" :style="themeVars">
|
|
48
|
-
<
|
|
48
|
+
<ChartContainer width="100%" :height="height">
|
|
49
49
|
<VccsRadarChart :data="data">
|
|
50
50
|
<PolarGrid stroke="var(--vc-grid-color)" />
|
|
51
51
|
<PolarAngleAxis :data-key="angleKey" :tick-formatter="angleFormatter" />
|
|
@@ -85,6 +85,6 @@ const themeVars = computed(() => themeToVars(props.theme));
|
|
|
85
85
|
</template>
|
|
86
86
|
</Legend>
|
|
87
87
|
</VccsRadarChart>
|
|
88
|
-
</
|
|
88
|
+
</ChartContainer>
|
|
89
89
|
</div>
|
|
90
90
|
</template>
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
Legend,
|
|
5
5
|
RadialBar,
|
|
6
6
|
RadialBarChart as VccsRadialBarChart,
|
|
7
|
-
ResponsiveContainer,
|
|
8
7
|
Tooltip
|
|
9
8
|
} from "vccs";
|
|
9
|
+
import ChartContainer from "./internal/ChartContainer";
|
|
10
10
|
import ChartTooltip from "./internal/ChartTooltip.vue";
|
|
11
11
|
import ChartLegend from "./internal/ChartLegend.vue";
|
|
12
12
|
import { categoriesToSeries } from "../utils/categories";
|
|
@@ -49,7 +49,7 @@ const legendWrapperStyle = computed(
|
|
|
49
49
|
|
|
50
50
|
<template>
|
|
51
51
|
<div class="vue-chrts" :style="themeVars">
|
|
52
|
-
<
|
|
52
|
+
<ChartContainer width="100%" :height="height">
|
|
53
53
|
<VccsRadialBarChart
|
|
54
54
|
:data="bars"
|
|
55
55
|
:inner-radius="innerRadius ?? '30%'"
|
|
@@ -76,6 +76,6 @@ const legendWrapperStyle = computed(
|
|
|
76
76
|
</template>
|
|
77
77
|
</Legend>
|
|
78
78
|
</VccsRadialBarChart>
|
|
79
|
-
</
|
|
79
|
+
</ChartContainer>
|
|
80
80
|
</div>
|
|
81
81
|
</template>
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
CartesianGrid,
|
|
5
5
|
Legend,
|
|
6
6
|
ReferenceLine,
|
|
7
|
-
ResponsiveContainer,
|
|
8
7
|
Tooltip,
|
|
9
8
|
XAxis,
|
|
10
9
|
YAxis
|
|
11
10
|
} from "vccs";
|
|
11
|
+
import ChartContainer from "./ChartContainer";
|
|
12
12
|
import { legendPositionToLegendProps, resolveLegendWrapperStyle } from "../../utils/legend";
|
|
13
13
|
import {
|
|
14
14
|
AXIS_TICK_MARGIN,
|
|
@@ -212,7 +212,7 @@ const resolvedYAxes = computed(() => {
|
|
|
212
212
|
|
|
213
213
|
<template>
|
|
214
214
|
<div class="vue-chrts" :style="rootStyle">
|
|
215
|
-
<
|
|
215
|
+
<ChartContainer width="100%" :height="height">
|
|
216
216
|
<component :is="container" v-bind="mergedContainerProps">
|
|
217
217
|
<CartesianGrid
|
|
218
218
|
v-if="showXGrid || showYGrid"
|
|
@@ -316,6 +316,6 @@ const resolvedYAxes = computed(() => {
|
|
|
316
316
|
</template>
|
|
317
317
|
</Legend>
|
|
318
318
|
</component>
|
|
319
|
-
</
|
|
319
|
+
</ChartContainer>
|
|
320
320
|
</div>
|
|
321
321
|
</template>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type PropType, type VNode } from "vue";
|
|
2
|
+
type Size = number | string;
|
|
3
|
+
/**
|
|
4
|
+
* Drop-in replacement for `vccs`' `ResponsiveContainer`.
|
|
5
|
+
*
|
|
6
|
+
* Upstream renders children through `resolveDynamicComponent(() => renderChildren())`,
|
|
7
|
+
* which produces a new component type every render and so unmounts + remounts the
|
|
8
|
+
* whole chart subtree. Charts that dispatch on `mouseenter` (radial bar, radar) then
|
|
9
|
+
* loop forever — remount recreates the `<path>` under the cursor, which refires
|
|
10
|
+
* `mouseenter` — and freeze the tab. Rendering the cloned children directly keeps
|
|
11
|
+
* the subtree stable.
|
|
12
|
+
*/
|
|
13
|
+
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
14
|
+
width: {
|
|
15
|
+
type: PropType<Size>;
|
|
16
|
+
default: string;
|
|
17
|
+
};
|
|
18
|
+
height: {
|
|
19
|
+
type: PropType<Size>;
|
|
20
|
+
default: string;
|
|
21
|
+
};
|
|
22
|
+
aspect: {
|
|
23
|
+
type: NumberConstructor;
|
|
24
|
+
default: undefined;
|
|
25
|
+
};
|
|
26
|
+
minWidth: {
|
|
27
|
+
type: PropType<Size>;
|
|
28
|
+
default: number;
|
|
29
|
+
};
|
|
30
|
+
minHeight: {
|
|
31
|
+
type: PropType<Size>;
|
|
32
|
+
default: undefined;
|
|
33
|
+
};
|
|
34
|
+
maxHeight: {
|
|
35
|
+
type: PropType<Size>;
|
|
36
|
+
default: undefined;
|
|
37
|
+
};
|
|
38
|
+
id: {
|
|
39
|
+
type: StringConstructor;
|
|
40
|
+
default: undefined;
|
|
41
|
+
};
|
|
42
|
+
onResize: {
|
|
43
|
+
type: PropType<(width: number, height: number) => void>;
|
|
44
|
+
default: undefined;
|
|
45
|
+
};
|
|
46
|
+
}>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
49
|
+
width: {
|
|
50
|
+
type: PropType<Size>;
|
|
51
|
+
default: string;
|
|
52
|
+
};
|
|
53
|
+
height: {
|
|
54
|
+
type: PropType<Size>;
|
|
55
|
+
default: string;
|
|
56
|
+
};
|
|
57
|
+
aspect: {
|
|
58
|
+
type: NumberConstructor;
|
|
59
|
+
default: undefined;
|
|
60
|
+
};
|
|
61
|
+
minWidth: {
|
|
62
|
+
type: PropType<Size>;
|
|
63
|
+
default: number;
|
|
64
|
+
};
|
|
65
|
+
minHeight: {
|
|
66
|
+
type: PropType<Size>;
|
|
67
|
+
default: undefined;
|
|
68
|
+
};
|
|
69
|
+
maxHeight: {
|
|
70
|
+
type: PropType<Size>;
|
|
71
|
+
default: undefined;
|
|
72
|
+
};
|
|
73
|
+
id: {
|
|
74
|
+
type: StringConstructor;
|
|
75
|
+
default: undefined;
|
|
76
|
+
};
|
|
77
|
+
onResize: {
|
|
78
|
+
type: PropType<(width: number, height: number) => void>;
|
|
79
|
+
default: undefined;
|
|
80
|
+
};
|
|
81
|
+
}>> & Readonly<{}>, {
|
|
82
|
+
width: Size;
|
|
83
|
+
height: Size;
|
|
84
|
+
aspect: number;
|
|
85
|
+
minWidth: Size;
|
|
86
|
+
minHeight: Size;
|
|
87
|
+
maxHeight: Size;
|
|
88
|
+
id: string;
|
|
89
|
+
onResize: (width: number, height: number) => void;
|
|
90
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
91
|
+
export default _default;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cloneVNode,
|
|
3
|
+
computed,
|
|
4
|
+
defineComponent,
|
|
5
|
+
Fragment,
|
|
6
|
+
h,
|
|
7
|
+
onBeforeUnmount,
|
|
8
|
+
onMounted,
|
|
9
|
+
ref
|
|
10
|
+
} from "vue";
|
|
11
|
+
const isPercent = (value) => typeof value === "string" && value.endsWith("%");
|
|
12
|
+
const toCssSize = (value) => value == null ? void 0 : typeof value === "number" ? `${value}px` : value;
|
|
13
|
+
function flatten(vnodes) {
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const vnode of vnodes) {
|
|
16
|
+
if (vnode.type === Fragment && Array.isArray(vnode.children))
|
|
17
|
+
result.push(...flatten(vnode.children));
|
|
18
|
+
else result.push(vnode);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
export default defineComponent({
|
|
23
|
+
name: "ChartContainer",
|
|
24
|
+
inheritAttrs: false,
|
|
25
|
+
props: {
|
|
26
|
+
width: { type: [Number, String], default: "100%" },
|
|
27
|
+
height: { type: [Number, String], default: "100%" },
|
|
28
|
+
aspect: { type: Number, default: void 0 },
|
|
29
|
+
minWidth: { type: [Number, String], default: 0 },
|
|
30
|
+
minHeight: { type: [Number, String], default: void 0 },
|
|
31
|
+
maxHeight: { type: [Number, String], default: void 0 },
|
|
32
|
+
id: { type: String, default: void 0 },
|
|
33
|
+
onResize: { type: Function, default: void 0 }
|
|
34
|
+
},
|
|
35
|
+
setup(props, { slots }) {
|
|
36
|
+
const containerRef = ref();
|
|
37
|
+
const sizes = ref({ width: -1, height: -1 });
|
|
38
|
+
const calculatedWidth = computed(
|
|
39
|
+
() => isPercent(props.width) ? sizes.value.width : Number(props.width)
|
|
40
|
+
);
|
|
41
|
+
const calculatedHeight = computed(() => {
|
|
42
|
+
if (props.aspect && props.aspect > 0 && (props.height == null || props.height === "auto"))
|
|
43
|
+
return calculatedWidth.value / props.aspect;
|
|
44
|
+
return isPercent(props.height) ? sizes.value.height : Number(props.height);
|
|
45
|
+
});
|
|
46
|
+
const finalWidth = computed(() => {
|
|
47
|
+
if (props.aspect && props.aspect > 0 && (props.width == null || props.width === "auto"))
|
|
48
|
+
return calculatedHeight.value * props.aspect;
|
|
49
|
+
return calculatedWidth.value;
|
|
50
|
+
});
|
|
51
|
+
const isReady = computed(() => sizes.value.width >= 0 && sizes.value.height >= 0);
|
|
52
|
+
const containerStyle = computed(() => ({
|
|
53
|
+
width: toCssSize(props.width),
|
|
54
|
+
height: toCssSize(props.height),
|
|
55
|
+
minWidth: toCssSize(props.minWidth),
|
|
56
|
+
minHeight: toCssSize(props.minHeight),
|
|
57
|
+
maxHeight: toCssSize(props.maxHeight)
|
|
58
|
+
}));
|
|
59
|
+
function setSize(width, height) {
|
|
60
|
+
const next = { width: Math.round(width), height: Math.round(height) };
|
|
61
|
+
if (next.width === sizes.value.width && next.height === sizes.value.height) return;
|
|
62
|
+
sizes.value = next;
|
|
63
|
+
props.onResize?.(next.width, next.height);
|
|
64
|
+
}
|
|
65
|
+
let observer = null;
|
|
66
|
+
onMounted(() => {
|
|
67
|
+
const el = containerRef.value;
|
|
68
|
+
if (!el) return;
|
|
69
|
+
const rect = el.getBoundingClientRect();
|
|
70
|
+
setSize(rect.width, rect.height);
|
|
71
|
+
observer = new ResizeObserver((entries) => {
|
|
72
|
+
const { width, height } = entries[0].contentRect;
|
|
73
|
+
setSize(width, height);
|
|
74
|
+
});
|
|
75
|
+
observer.observe(el);
|
|
76
|
+
});
|
|
77
|
+
onBeforeUnmount(() => {
|
|
78
|
+
observer?.disconnect();
|
|
79
|
+
observer = null;
|
|
80
|
+
});
|
|
81
|
+
function renderChildren() {
|
|
82
|
+
if (!isReady.value) return [];
|
|
83
|
+
const raw = slots.default?.();
|
|
84
|
+
if (!raw) return [];
|
|
85
|
+
return flatten(raw).map(
|
|
86
|
+
(child, index) => cloneVNode(child, {
|
|
87
|
+
width: finalWidth.value,
|
|
88
|
+
height: calculatedHeight.value,
|
|
89
|
+
key: child.key || `chart-container-child-${index}`,
|
|
90
|
+
style: {
|
|
91
|
+
maxWidth: `${sizes.value.width}px`,
|
|
92
|
+
maxHeight: `${sizes.value.height}px`,
|
|
93
|
+
width: "100%",
|
|
94
|
+
height: "100%",
|
|
95
|
+
...child.props?.style
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return () => h(
|
|
101
|
+
"div",
|
|
102
|
+
{
|
|
103
|
+
id: props.id,
|
|
104
|
+
ref: containerRef,
|
|
105
|
+
class: "vcharts-responsive-container",
|
|
106
|
+
style: containerStyle.value
|
|
107
|
+
},
|
|
108
|
+
renderChildren()
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
@@ -72,14 +72,14 @@ export default { name: "FunnelLayeredShape" };
|
|
|
72
72
|
:x2="geometry.startX"
|
|
73
73
|
:y1="geometry.dividerStartY"
|
|
74
74
|
:y2="geometry.dividerEndY"
|
|
75
|
-
|
|
75
|
+
stroke="var(--vc-surface-bg)"
|
|
76
76
|
:stroke-width="5"
|
|
77
77
|
/>
|
|
78
78
|
|
|
79
79
|
<text
|
|
80
80
|
:x="geometry.middleX"
|
|
81
81
|
:y="geometry.topLabelY"
|
|
82
|
-
|
|
82
|
+
fill="var(--vc-axis-label-color)"
|
|
83
83
|
:font-size="16"
|
|
84
84
|
:font-weight="700"
|
|
85
85
|
text-anchor="middle"
|
|
@@ -93,16 +93,16 @@ export default { name: "FunnelLayeredShape" };
|
|
|
93
93
|
:width="geometry.badgeWidth"
|
|
94
94
|
:height="30"
|
|
95
95
|
:rx="15"
|
|
96
|
-
|
|
96
|
+
fill="var(--vc-surface-bg)"
|
|
97
97
|
fill-opacity="0.82"
|
|
98
|
-
|
|
98
|
+
stroke="var(--vc-axis-line-color)"
|
|
99
99
|
stroke-opacity="0.7"
|
|
100
100
|
:stroke-width="1"
|
|
101
101
|
/>
|
|
102
102
|
<text
|
|
103
103
|
:x="geometry.middleX"
|
|
104
104
|
:y="geometry.centerY + 5"
|
|
105
|
-
|
|
105
|
+
fill="var(--vc-axis-label-color)"
|
|
106
106
|
:font-size="14"
|
|
107
107
|
:font-weight="600"
|
|
108
108
|
text-anchor="middle"
|
|
@@ -113,7 +113,7 @@ export default { name: "FunnelLayeredShape" };
|
|
|
113
113
|
<text
|
|
114
114
|
:x="geometry.middleX"
|
|
115
115
|
:y="geometry.bottomLabelY"
|
|
116
|
-
|
|
116
|
+
fill="var(--vc-tick-color)"
|
|
117
117
|
:font-size="15"
|
|
118
118
|
:font-weight="500"
|
|
119
119
|
text-anchor="middle"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-charts",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.2",
|
|
4
4
|
"description": "Beautiful chart components for Nuxt (vccs engine) — Area, Bar, Line, Donut, Bubble, Radar, Radial Bar, Funnel, Candlestick, Status Tracker",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Dennis Adriaansen <adriaansendennis@gmail.com>",
|
|
@@ -46,6 +46,20 @@
|
|
|
46
46
|
"files": [
|
|
47
47
|
"dist"
|
|
48
48
|
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"prepack": "nuxt-module-build build",
|
|
51
|
+
"dev": "nuxi dev playground",
|
|
52
|
+
"build": "nuxt-module-build build",
|
|
53
|
+
"build:playground": "nuxi build playground",
|
|
54
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
55
|
+
"release": "node ../../tools/release.mjs --package nuxt-charts",
|
|
56
|
+
"lint": "eslint .",
|
|
57
|
+
"typecheck": "pnpm run test:types",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:watch": "vitest watch",
|
|
60
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
61
|
+
"release:dry": "node ../../tools/release.mjs --package nuxt-charts --dry-run"
|
|
62
|
+
},
|
|
49
63
|
"dependencies": {
|
|
50
64
|
"@types/d3-array": "^3.2.2",
|
|
51
65
|
"@types/d3-scale": "^4.0.9",
|
|
@@ -58,7 +72,7 @@
|
|
|
58
72
|
"d3-shape": "^3.2.0",
|
|
59
73
|
"d3-zoom": "^3.0.0",
|
|
60
74
|
"motion-v": "^2.3.0",
|
|
61
|
-
"vccs": "^0.
|
|
75
|
+
"vccs": "^0.5.0"
|
|
62
76
|
},
|
|
63
77
|
"devDependencies": {
|
|
64
78
|
"@nuxt/devtools": "^3.1.1",
|
|
@@ -67,10 +81,10 @@
|
|
|
67
81
|
"@nuxt/kit": "^4.3.0",
|
|
68
82
|
"@nuxt/module-builder": "^1.0.2",
|
|
69
83
|
"@nuxt/schema": "^4.3.0",
|
|
70
|
-
"@nuxt/test-utils": "^
|
|
84
|
+
"@nuxt/test-utils": "^4.2.0",
|
|
71
85
|
"@tailwindcss/vite": "^4.2.2",
|
|
72
86
|
"@types/node": "latest",
|
|
73
|
-
"@vitejs/plugin-vue": "^
|
|
87
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
74
88
|
"@vue/test-utils": "^2.4.11",
|
|
75
89
|
"eslint": "^9.39.2",
|
|
76
90
|
"happy-dom": "^20.10.6",
|
|
@@ -78,23 +92,12 @@
|
|
|
78
92
|
"tailwindcss": "^4.2.2",
|
|
79
93
|
"typescript": "~5.9.3",
|
|
80
94
|
"vitest": "^4.0.18",
|
|
95
|
+
"vue": "^3.5.42",
|
|
81
96
|
"vue-tsc": "^3.2.4"
|
|
82
97
|
},
|
|
98
|
+
"packageManager": "pnpm@10.33.0",
|
|
83
99
|
"publishConfig": {
|
|
84
100
|
"access": "public",
|
|
85
101
|
"tag": "beta"
|
|
86
|
-
},
|
|
87
|
-
"scripts": {
|
|
88
|
-
"dev": "nuxi dev playground",
|
|
89
|
-
"build": "nuxt-module-build build",
|
|
90
|
-
"build:playground": "nuxi build playground",
|
|
91
|
-
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
92
|
-
"release": "node ../../tools/release.mjs --package nuxt-charts",
|
|
93
|
-
"lint": "eslint .",
|
|
94
|
-
"typecheck": "pnpm run test:types",
|
|
95
|
-
"test": "vitest run",
|
|
96
|
-
"test:watch": "vitest watch",
|
|
97
|
-
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
98
|
-
"release:dry": "node ../../tools/release.mjs --package nuxt-charts --dry-run"
|
|
99
102
|
}
|
|
100
|
-
}
|
|
103
|
+
}
|