Skip to content

Commit 9d077c2

Browse files
authored
Merge pull request #127 from graphieros/ft-funnel
Ft funnel
2 parents cc775f1 + 4afbdc4 commit 9d077c2

16 files changed

+1420
-24
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# vue-data-ui
1010

1111
[![npm](https://img.shields.io/npm/v/vue-data-ui)](https://github.com/graphieros/vue-data-ui)
12-
[![Static Badge](https://img.shields.io/badge/components-58-blue)](https://github.com/graphieros/vue-data-ui)
12+
[![Static Badge](https://img.shields.io/badge/components-59-blue)](https://github.com/graphieros/vue-data-ui)
1313
[![GitHub issues](https://img.shields.io/github/issues/graphieros/vue-data-ui)](https://github.com/graphieros/vue-data-ui/issues)
1414
[![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/graphieros/vue-data-ui?tab=MIT-1-ov-file#readme)
1515
[![MadeWithVueJs.com shield](https://madewithvuejs.com/storage/repo-shields/4526-shield.svg)](https://madewithvuejs.com/p/vue-data-ui/shield-link)
@@ -30,6 +30,7 @@ Available components
3030
- [VueUiDonut](https://vue-data-ui.graphieros.com/docs#vue-ui-donut)
3131
- [VueUiDumbbell](https://vue-data-ui.graphieros.com/docs#vue-ui-dumbbell)
3232
- [VueUiFlow](https://vue-data-ui.graphieros.com/docs#vue-ui-flow)
33+
- [VueUiFunnel](https://vue-data-ui.graphieros.com/docs#vue-ui-funnel)
3334
- [VueUiGalaxy](https://vue-data-ui.graphieros.com/docs#vue-ui-galaxy)
3435
- [VueUiGauge](https://vue-data-ui.graphieros.com/docs#vue-ui-gauge)
3536
- [VueUiHeatmap](https://vue-data-ui.graphieros.com/docs#vue-ui-heatmap)
@@ -209,7 +210,9 @@ The svg slot also works when using the VueDataUi universal component, if the com
209210

210211
All charts expose a #legend slot except for:
211212

213+
- VueUiDumbbell
212214
- VueUiFlow
215+
- VueUiFunnel
213216
- VueUiHeatmap
214217
- VueUiRelationCircle
215218
- VueUiSparkHistogram
@@ -218,10 +221,9 @@ All charts expose a #legend slot except for:
218221
- VueUiSparkgauge
219222
- VueUiSparkline
220223
- VueUiThermometer
224+
- VueUiTimer
221225
- VueUiTiremarks
222226
- VueUiWheel
223-
- VueUiDumbbell
224-
- VueUiTimer
225227

226228
The legend slot also works when using the VueDataUi universal component, if the component it wraps supports it.
227229
It is recommended to set the show legend config attribute to false, to hide the default legend.
@@ -415,7 +417,8 @@ From the dataset you pass into the props, this component will produce the most a
415417
| `VueUiDonutEvolution` | `VueUiDonutEvolutionDatasetItem[]` | `VueUiDonutEvolutionConfig` | `@selectLegend`, `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable` | `#svg`, `#legend`, `#reset-action`, `#watermark` |||
416418
| `VueUiDonut` | `VueUiDonutDatasetItem[]` | `VueUiDonutConfig` | `@selectDatapoint`, `@selectLegend`, `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable`, `toggleLabels`, `toggleTooltip` | `#svg`, `#legend`, `#dataLabel`, `#tooltip-before`, `#tooltip-after`, `#plot-comment`, `#watermark` |||
417419
| `VueUiDumbbell` | `VueUiDumbbellDataset[]` | `VueUiDumbbellConfig` | `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable` | `#svg`, `#legend`, `#watermark` |||
418-
| `VueUiFlow` | `VueUiFlowDatasetItem[]` | `VueUiFlowConfig` | `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable` | `#svg`,, `#watermark` |||
420+
| `VueUiFlow` | `VueUiFlowDatasetItem[]` | `VueUiFlowConfig` | `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable` | `#svg`, `#watermark` |||
421+
| `VueUiFunnel` | `VueUiFunnelDatasetItem[]` | `VueUiFunnelConfig` | `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable` | `#svg`, `#watermark` |||
419422
| `VueUiGalaxy` | `VueUiGalaxyDatasetItem[]` | `VueUiGalaxyConfig` | `@selectDatapoint`, `@selectLegend`, `getData`, `generatePdf`, `generateCsv`, `generateImage`, `toggleTable`, `toggleTooltip` | `#svg`, `#legend`,`#tooltip-before`, `#tooltip-after` |||
420423
| `VueUiGauge` | `VueUiGaugeDataset` | `VueUiGaugeConfig` | `generatePdf`, `generateImage` | `#svg`, `#legend`, `#watermark` |||
421424
| `VueUiHeatmap` | `VueUiHeatmapDatasetItem[]` | `VueUiHeatmapConfig` | `generatePdf`, `generateCsv`, `generateImage`, `toggleTable`, `toggleTooltip` | `#svg`, `#tooltip-before`, `#tooltip-after`, `#watermark` |||
@@ -549,6 +552,7 @@ User options actions available per chart:
549552
| VueUiDonutEvolution | optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
550553
| VueUiDumbbell | optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
551554
| VueUiFlow | optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
555+
| VueUiFunnel | optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
552556
| VueUiGalaxy | optionTooltip, optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
553557
| VueUiGauge | optionPdf, optionImg, optionFullscreen, optionAnnotator |
554558
| VueUiHeatmap | optionTooltip, optionPdf, optionImg, optionCsv, optionTable, optionFullscreen, optionAnnotator |
@@ -637,6 +641,7 @@ However the folowing charts can be made fully responsive, making them better to
637641
| VueUiDonutEvolution | - |
638642
| VueUiDumbbell ||
639643
| VueUiFlow | - |
644+
| VueUiFunnel ||
640645
| VueUiGalaxy | - |
641646
| VueUiGauge ||
642647
| VueUiHeatmap | - |

TestingArena/ArenaVueUiFunnel.vue

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
<script setup>
2+
import { ref, computed } from "vue";
3+
import LocalVueUiFunnel from '../src/components/vue-ui-funnel.vue';
4+
import LocalVueDataUi from '../src/components/vue-data-ui.vue';
5+
import Box from "./Box.vue";
6+
import convertArrayToObject from "./convertModel";
7+
import { useArena } from "../src/useArena"
8+
9+
const { local, build, vduiLocal, vduiBuild, toggleTable } = useArena()
10+
11+
const dataset = ref([
12+
{
13+
name: 'Lead',
14+
value: 7745.8234576
15+
},
16+
{
17+
name: 'Opportunity',
18+
value: 5468
19+
},
20+
{
21+
name: 'Qualified',
22+
value: 4238
23+
},
24+
{
25+
name: 'Sold',
26+
value: 2025
27+
},
28+
{
29+
name: 'Retained',
30+
value: 1520
31+
},
32+
])
33+
34+
const model = ref([
35+
{ key: 'responsive', def: false, type: 'checkbox'},
36+
{ key: 'useCssAnimation', def: true, type: 'checkbox' },
37+
{ key: 'style.chart.backgroundColor', def: '#FFFFFF', type: 'color' },
38+
{ key: 'style.chart.color', def: '#1A1A1A', type: 'color' },
39+
{ key: 'style.chart.width', def: 600, type: 'range', min: 300, max: 1000 },
40+
{ key: 'style.chart.height', def: 500, type: 'range', min: 300, max: 1000 },
41+
42+
{ key: 'style.chart.title.text', def: 'Title', type: 'text', label: 'textContent', category: 'title' },
43+
{ key: 'style.chart.title.color', def: '#1A1A1A', type: 'color', label: 'textColor', category: 'title' },
44+
{ key: 'style.chart.title.fontSize', def: 20, type: 'number', min: 6, max: 48, label: 'fontSize', category: 'title' },
45+
{ key: 'style.chart.title.bold', def: true, type: 'checkbox', label: 'bold', category: 'title' },
46+
{ key: 'style.chart.title.textAlign', def: 'center', type: 'select', options: ['left', 'center', 'right']},
47+
{ key: 'style.chart.title.paddingLeft', def: 0, type: 'number', min: 0, max: 24 },
48+
{ key: 'style.chart.title.paddingRight', def: 0, type: 'number', min: 0, max: 24 },
49+
50+
{ key: 'style.chart.title.subtitle.text', def: 'Lorem ipsum dolor sit amet', type: 'text', label: 'textContent', category: 'subtitle' },
51+
{ key: 'style.chart.title.subtitle.color', def: '#A1A1A1', type: 'color', label: 'textColor', category: 'subtitle' },
52+
{ key: 'style.chart.title.subtitle.fontSize', def: 16, type: 'number', min: 6, max: 42, label: 'fontSize', category: 'subtitle' },
53+
{ key: 'style.chart.title.subtitle.bold', def: false, type: 'checkbox', label: 'bold', category: 'subtitle' },
54+
55+
{ key: 'style.chart.padding.top', def: 12, type: 'number', min: 0, max: 200 },
56+
{ key: 'style.chart.padding.right', def: 128, type: 'number', min: 0, max: 200 },
57+
{ key: 'style.chart.padding.bottom', def: 24, type: 'number', min: 0, max: 200 },
58+
{ key: 'style.chart.padding.left', def: 24, type: 'number', min: 0, max: 200 },
59+
60+
{ key: 'style.chart.barCircleSpacingRatio', def: 0.05, type: 'range', min: 0, max: 0.5, step: 0.01},
61+
62+
{ key: 'style.chart.circles.stroke', def: '#FFFFFF', type: 'color' },
63+
{ key: 'style.chart.circles.strokeWidth', def: 1, type: 'range', min: 0, max: 12 },
64+
{ key: 'style.chart.circles.dataLabels.fontSize', def: 16, min: 8, max: 48, type: 'range'},
65+
{ key: 'style.chart.circles.dataLabels.offsetY', def: 0, min: -100, max: 100, type: 'number'},
66+
{ key: 'style.chart.circles.dataLabels.adaptColorToBackground', def: true, type: 'checkbox'},
67+
{ key: 'style.chart.circles.dataLabels.color', def: '#1A1A1A', type: 'color'},
68+
{ key: 'style.chart.circles.dataLabels.rounding', def: 1, type: 'number', min: 0, max: 6},
69+
{ key: 'style.chart.circles.dataLabels.bold', def: true, type: 'checkbox'},
70+
71+
{ key: 'style.chart.circleLinks.show', def: true, type: 'checkbox'},
72+
{ key: 'style.chart.circleLinks.color', def: '#E1E5E8', type: 'color'},
73+
{ key: 'style.chart.circleLinks.widthRatio', def: 1, type: 'range', min: 0.1, max: 2, step: 0.01},
74+
75+
{ key: 'style.chart.area.show', def: true, type: 'checkbox' },
76+
{ key: 'style.chart.area.color', def: '#e1e5e8', type: 'color' },
77+
78+
{ key: 'style.chart.bars.stroke', def: '#FFFFFF', type: 'color' },
79+
{ key: 'style.chart.bars.defaultColor', def: '#1f77b4', type: 'color'},
80+
{ key: 'style.chart.bars.strokeWidth', def: 1, type: 'range', min: 0, max: 12 },
81+
{ key: 'style.chart.bars.gapRatio', def: 0.2, type: 'range', min: 0, max: 1, step: 0.01 },
82+
{ key: 'style.chart.bars.borderRadius', def: 3, min: 0, max: 24, type: 'range'},
83+
84+
{ key: 'style.chart.bars.dataLabels.name.fontSize', def: 16, type: 'number', min: 8, max: 42 },
85+
{ key: 'style.chart.bars.dataLabels.name.color', def: '#1A1A1A', type: 'color' },
86+
{ key: 'style.chart.bars.dataLabels.name.bold', def: true, type: 'checkbox' },
87+
{ key: 'style.chart.bars.dataLabels.name.offsetX', def: 0, type: 'number', min: -100, max: 100},
88+
{ key: 'style.chart.bars.dataLabels.name.offsetY', def: 0, type: 'number', min: -100, max: 100},
89+
90+
{ key: 'style.chart.bars.dataLabels.value.fontSize', def: 16, type: 'number', min: 8, max: 42},
91+
{ key: 'style.chart.bars.dataLabels.value.rounding', def: 0, type: 'number', min: 0, max: 6 },
92+
{ key: 'style.chart.bars.dataLabels.value.bold', def: false, type: 'checkbox'},
93+
{ key: 'style.chart.bars.dataLabels.value.color', def: '#1A1A1A', type: 'color' },
94+
{ key: 'style.chart.bars.dataLabels.value.prefix', def: 'P', type: 'text'},
95+
{ key: 'style.chart.bars.dataLabels.value.suffix', def: 'S', type: 'text'},
96+
{ key: 'style.chart.bars.dataLabels.value.offsetX', def: 0, type: 'number', min: -100, max: 100 },
97+
{ key: 'style.chart.bars.dataLabels.value.offsetY', def: 0, type: 'number', min: -100, max: 100 },
98+
])
99+
100+
const themeOptions = ref([
101+
"",
102+
"hack",
103+
"zen",
104+
"concrete",
105+
"default"
106+
])
107+
108+
const currentTheme = ref(themeOptions.value[4])
109+
110+
const config = computed(() => {
111+
const c = convertArrayToObject(model.value);
112+
113+
return {
114+
theme: currentTheme.value,
115+
...c,
116+
style: {
117+
...c.style,
118+
chart: {
119+
...c.style.chart,
120+
circles: {
121+
...c.style.chart.circles,
122+
dataLabels: {
123+
...c.style.chart.circles.dataLabels,
124+
// formatter: ({ value, config }) => {
125+
// console.log(config)
126+
// return `CIR ${value}`
127+
// }
128+
}
129+
},
130+
bars: {
131+
...c.style.chart.bars,
132+
dataLabels: {
133+
...c.style.chart.bars.dataLabels,
134+
value: {
135+
...c.style.chart.bars.dataLabels.value,
136+
// formatter: ({ value, config }) => {
137+
// console.log(config)
138+
// return `BAR ${value}`
139+
// }
140+
}
141+
}
142+
}
143+
}
144+
}
145+
}
146+
})
147+
148+
const step = ref(0);
149+
150+
</script>
151+
152+
<template>
153+
<div style="margin: 12px 0; color: white">
154+
Theme:
155+
<select v-model="currentTheme" @change="step += 1">
156+
<option v-for="opt in themeOptions">{{ opt }}</option>
157+
</select>
158+
</div>
159+
160+
<div style="width: 600px; height: 600px; resize: both; overflow: auto; background: white">
161+
<LocalVueUiFunnel :key="`responsive_${step}`" :dataset="dataset" :config="{
162+
...config,
163+
responsive: true
164+
}">
165+
</LocalVueUiFunnel>
166+
</div>
167+
168+
<Box>
169+
<template #title>VueUiFunnel</template>
170+
171+
<template #local>
172+
<LocalVueUiFunnel :dataset="dataset" :config="config">
173+
<template #source>
174+
#source
175+
</template>
176+
<template #watermark="{ isPrinting }">
177+
<div v-if="isPrinting" style="font-size: 100px; opacity: 0.1; transform: rotate(-10deg)">
178+
WATERMARK
179+
</div>
180+
</template>
181+
<template #optionPdf>
182+
PRINT PDF
183+
</template>
184+
<template #svg="{ svg }">
185+
<g style="pointer-events: none;">
186+
<circle :cx="svg.width - 30" :cy="svg.height / 2" :r="30" fill="#42d392" />
187+
<text :x="svg.width - 30" :y="svg.height / 2" text-anchor="middle">#SVG</text>
188+
</g>
189+
</template>
190+
</LocalVueUiFunnel>
191+
</template>
192+
193+
<template #VDUI-local>
194+
<LocalVueDataUi component="VueUiFunnel" :dataset="dataset" :config="config">
195+
<template #source>
196+
#source
197+
</template>
198+
<template #watermark="{ isPrinting }">
199+
<div v-if="isPrinting" style="font-size: 100px; opacity: 0.1; transform: rotate(-10deg)">
200+
WATERMARK
201+
</div>
202+
</template>
203+
<template #optionPdf>
204+
PRINT PDF
205+
</template>
206+
<template #svg="{ svg }">
207+
<g style="pointer-events: none;">
208+
<circle :cx="svg.width - 30" :cy="svg.height / 2" :r="30" fill="#42d392" />
209+
<text :x="svg.width - 30" :y="svg.height / 2" text-anchor="middle">#SVG</text>
210+
</g>
211+
</template>
212+
</LocalVueDataUi>
213+
</template>
214+
215+
<template #build>
216+
<VueUiFunnel :dataset="dataset" :config="config">
217+
<template #source>
218+
#source
219+
</template>
220+
<template #watermark="{ isPrinting }">
221+
<div v-if="isPrinting" style="font-size: 100px; opacity: 0.1; transform: rotate(-10deg)">
222+
WATERMARK
223+
</div>
224+
</template>
225+
<template #optionPdf>
226+
PRINT PDF
227+
</template>
228+
<template #svg="{ svg }">
229+
<g style="pointer-events: none;">
230+
<circle :cx="svg.width - 30" :cy="svg.height / 2" :r="30" fill="#42d392" />
231+
<text :x="svg.width - 30" :y="svg.height / 2" text-anchor="middle">#SVG</text>
232+
</g>
233+
</template>
234+
</VueUiFunnel>
235+
</template>
236+
237+
<template #VDUI-build>
238+
<VueDataUi component="VueUiFunnel" :dataset="dataset" :config="config">
239+
<template #source>
240+
#source
241+
</template>
242+
<template #watermark="{ isPrinting }">
243+
<div v-if="isPrinting" style="font-size: 100px; opacity: 0.1; transform: rotate(-10deg)">
244+
WATERMARK
245+
</div>
246+
</template>
247+
<template #optionPdf>
248+
PRINT PDF
249+
</template>
250+
<template #svg="{ svg }">
251+
<g style="pointer-events: none;">
252+
<circle :cx="svg.width - 30" :cy="svg.height / 2" :r="30" fill="#42d392" />
253+
<text :x="svg.width - 30" :y="svg.height / 2" text-anchor="middle">#SVG</text>
254+
</g>
255+
</template>
256+
</VueDataUi>
257+
</template>
258+
259+
<template #knobs>
260+
<div
261+
style="display: flex; flex-direction: row; flex-wrap:wrap; align-items:center; width: 100%; color: #CCCCCC; gap:24px;">
262+
<div v-for="knob in model">
263+
<label style="font-size: 10px">{{ knob.key }}</label>
264+
<div
265+
style="display:flex; flex-direction:row; flex-wrap: wrap; align-items:center; gap:6px; height: 40px">
266+
<input v-if="!['none', 'select'].includes(knob.type)" :step="knob.step" :type="knob.type"
267+
:min="knob.min ?? 0" :max="knob.max ?? 0" v-model="knob.def" @change="step += 1">
268+
<select v-if="knob.type === 'select'" v-model="knob.def" @change="step += 1">
269+
<option v-for="opt in knob.options">{{ opt }}</option>
270+
</select>
271+
</div>
272+
</div>
273+
</div>
274+
</template>
275+
</Box>
276+
</template>

0 commit comments

Comments
 (0)