0
# Visual Effects and Progress
1
2
Drawing, progress indication, and QR code generation for enhanced user experience and visual feedback.
3
4
## Capabilities
5
6
### useDrauu
7
8
Interactive drawing and sketching using drauu library with canvas integration.
9
10
```typescript { .api }
11
/**
12
* Interactive drawing and sketching with canvas integration
13
* @param target - Target element (canvas or container) for drawing
14
* @param options - Drawing configuration options
15
* @returns Drawing control interface and event handlers
16
*/
17
function useDrauu(
18
target: MaybeComputedElementRef,
19
options?: UseDrauuOptions
20
): UseDrauuReturn;
21
22
interface UseDrauuReturn {
23
/** The drauu instance for direct access */
24
drauuInstance: Ref<Drauu | undefined>;
25
/** Load SVG drawing data */
26
load: (svg: string) => void;
27
/** Export current drawing as SVG string */
28
dump: () => string | undefined;
29
/** Clear all drawings */
30
clear: () => void;
31
/** Cancel current drawing operation */
32
cancel: () => void;
33
/** Undo last drawing action */
34
undo: () => boolean | undefined;
35
/** Redo previously undone action */
36
redo: () => boolean | undefined;
37
/** Whether undo is available */
38
canUndo: ShallowRef<boolean>;
39
/** Whether redo is available */
40
canRedo: ShallowRef<boolean>;
41
/** Current brush configuration */
42
brush: Ref<Brush>;
43
/** Drawing state change events */
44
onChanged: EventHookOn;
45
/** Drawing commit events */
46
onCommitted: EventHookOn;
47
/** Drawing start events */
48
onStart: EventHookOn;
49
/** Drawing end events */
50
onEnd: EventHookOn;
51
/** Drawing cancel events */
52
onCanceled: EventHookOn;
53
}
54
55
type UseDrauuOptions = Omit<Options, 'el'>;
56
57
// drauu library types
58
interface Options {
59
brush?: Brush;
60
acceptsInputTypes?: InputType[];
61
coordinate?: CoordinateType;
62
coordinateScale?: number | false;
63
coordinateTransform?: boolean | CoordinateTransform;
64
}
65
66
interface Brush {
67
mode?: DrawingMode;
68
color?: string;
69
size?: number;
70
cornerRadius?: number;
71
dasharray?: string | undefined;
72
arrowEnd?: boolean;
73
arrowStart?: boolean;
74
}
75
76
type DrawingMode = 'draw' | 'line' | 'rectangle' | 'ellipse' | 'stylus';
77
type InputType = 'mouse' | 'touch' | 'pen';
78
type CoordinateType = 'relative' | 'absolute';
79
```
80
81
**Usage Examples:**
82
83
```typescript
84
import { useDrauu } from "@vueuse/integrations/useDrauu";
85
import { ref, onMounted } from 'vue';
86
87
// Basic drawing setup
88
const canvasRef = ref<HTMLCanvasElement>();
89
const {
90
drauuInstance,
91
brush,
92
clear,
93
undo,
94
redo,
95
canUndo,
96
canRedo,
97
dump,
98
load,
99
onChanged
100
} = useDrauu(canvasRef, {
101
brush: {
102
mode: 'draw',
103
color: '#000000',
104
size: 3
105
}
106
});
107
108
// Change brush settings
109
const changeBrushColor = (color: string) => {
110
brush.value.color = color;
111
};
112
113
const changeBrushSize = (size: number) => {
114
brush.value.size = size;
115
};
116
117
const changeBrushMode = (mode: DrawingMode) => {
118
brush.value.mode = mode;
119
};
120
121
// Drawing tools
122
const clearCanvas = () => clear();
123
const undoLastAction = () => undo();
124
const redoAction = () => redo();
125
126
// Save and load drawings
127
const saveDrawing = () => {
128
const svgData = dump();
129
if (svgData) {
130
localStorage.setItem('saved-drawing', svgData);
131
}
132
};
133
134
const loadDrawing = () => {
135
const svgData = localStorage.getItem('saved-drawing');
136
if (svgData) {
137
load(svgData);
138
}
139
};
140
141
// Listen to drawing changes
142
onChanged(() => {
143
console.log('Drawing changed');
144
// Auto-save or validation logic
145
});
146
147
// Advanced brush configuration
148
const setupAdvancedBrush = () => {
149
brush.value = {
150
mode: 'line',
151
color: '#ff0000',
152
size: 5,
153
dasharray: '5,5', // Dashed line
154
arrowEnd: true, // Arrow at end
155
cornerRadius: 2 // Rounded corners
156
};
157
};
158
159
// Multiple drawing modes
160
const drawingModes = [
161
{ name: 'Pen', mode: 'draw' },
162
{ name: 'Line', mode: 'line' },
163
{ name: 'Rectangle', mode: 'rectangle' },
164
{ name: 'Ellipse', mode: 'ellipse' },
165
{ name: 'Stylus', mode: 'stylus' }
166
];
167
```
168
169
### useNProgress
170
171
Progress bar indication using NProgress library with reactive state management.
172
173
```typescript { .api }
174
/**
175
* Progress bar indication with reactive state management
176
* @param currentProgress - Current progress value (0-1 or null)
177
* @param options - NProgress configuration options
178
* @returns Progress control interface
179
*/
180
function useNProgress(
181
currentProgress?: MaybeRefOrGetter<number | null | undefined>,
182
options?: UseNProgressOptions
183
): {
184
/** Whether progress bar is currently showing */
185
isLoading: WritableComputedRef<boolean>;
186
/** Current progress value */
187
progress: Ref<number | null | undefined>;
188
/** Start progress indication */
189
start: () => NProgress;
190
/** Complete progress and hide bar */
191
done: (force?: boolean) => NProgress;
192
/** Remove progress bar from DOM */
193
remove: () => void;
194
};
195
196
type UseNProgressOptions = Partial<NProgressOptions>;
197
198
// NProgress configuration options
199
interface NProgressOptions {
200
/** Minimum progress value */
201
minimum?: number;
202
/** Animation template */
203
template?: string;
204
/** Easing function */
205
easing?: string;
206
/** Animation speed */
207
speed?: number;
208
/** Trickle animation */
209
trickle?: boolean;
210
/** Trickle speed */
211
trickleSpeed?: number;
212
/** Show spinner */
213
showSpinner?: boolean;
214
/** Barber pole moving animation */
215
barberPole?: boolean;
216
/** Parent element selector */
217
parent?: string;
218
}
219
```
220
221
**Usage Examples:**
222
223
```typescript
224
import { useNProgress } from "@vueuse/integrations/useNProgress";
225
import { ref } from 'vue';
226
227
// Basic progress indication
228
const { isLoading, start, done } = useNProgress();
229
230
// Show progress during async operations
231
const fetchData = async () => {
232
start();
233
try {
234
const response = await fetch('/api/data');
235
const data = await response.json();
236
return data;
237
} finally {
238
done();
239
}
240
};
241
242
// Controlled progress
243
const uploadProgress = ref(0);
244
const { progress, isLoading } = useNProgress(uploadProgress, {
245
minimum: 0.1,
246
speed: 200,
247
showSpinner: false
248
});
249
250
const simulateUpload = () => {
251
uploadProgress.value = 0;
252
const interval = setInterval(() => {
253
uploadProgress.value += 0.1;
254
if (uploadProgress.value >= 1) {
255
clearInterval(interval);
256
uploadProgress.value = null; // Hide progress bar
257
}
258
}, 100);
259
};
260
261
// Router integration
262
import { useRoute } from 'vue-router';
263
264
const route = useRoute();
265
const { start, done } = useNProgress();
266
267
// Show progress on route changes
268
watch(() => route.path, () => {
269
start();
270
nextTick(() => done());
271
});
272
273
// Custom configuration
274
const { start, done } = useNProgress(undefined, {
275
minimum: 0.2,
276
easing: 'ease',
277
speed: 500,
278
trickle: true,
279
trickleSpeed: 200,
280
showSpinner: true,
281
barberPole: true,
282
template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
283
});
284
285
// Global loading state
286
const globalLoading = ref(false);
287
const { isLoading: nprogress } = useNProgress();
288
289
// Sync with global state
290
watch(globalLoading, (loading) => {
291
nprogress.value = loading;
292
});
293
```
294
295
### useQRCode
296
297
QR code generation using qrcode library with reactive updates.
298
299
```typescript { .api }
300
/**
301
* QR code generation with reactive updates
302
* @param text - Text content to encode in QR code
303
* @param options - QR code generation options
304
* @returns Reactive data URL for QR code image
305
*/
306
function useQRCode(
307
text: MaybeRefOrGetter<string>,
308
options?: QRCode.QRCodeToDataURLOptions
309
): ShallowRef<string>;
310
311
// QR code generation options
312
namespace QRCode {
313
interface QRCodeToDataURLOptions {
314
/** Error correction level */
315
errorCorrectionLevel?: 'low' | 'medium' | 'quartile' | 'high';
316
/** QR code type (auto-detected if not specified) */
317
type?: 'image/png' | 'image/jpeg' | 'image/webp';
318
/** Rendered image quality (0.0 to 1.0) */
319
quality?: number;
320
/** Margin around QR code in modules */
321
margin?: number;
322
/** Scale factor for image size */
323
scale?: number;
324
/** Image width in pixels (overrides scale) */
325
width?: number;
326
/** Color options */
327
color?: {
328
/** Dark color (foreground) */
329
dark?: string;
330
/** Light color (background) */
331
light?: string;
332
};
333
}
334
}
335
```
336
337
**Usage Examples:**
338
339
```typescript
340
import { useQRCode } from "@vueuse/integrations/useQRCode";
341
import { ref, computed } from 'vue';
342
343
// Basic QR code generation
344
const text = ref('https://example.com');
345
const qrCode = useQRCode(text);
346
347
// QR code will be a data URL string like:
348
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK..."
349
350
// Dynamic QR code
351
const userInput = ref('');
352
const qrCodeUrl = useQRCode(userInput, {
353
width: 200,
354
margin: 2,
355
color: {
356
dark: '#000000',
357
light: '#FFFFFF'
358
}
359
});
360
361
// Contact information QR code
362
const contactInfo = computed(() => {
363
return [
364
'BEGIN:VCARD',
365
'VERSION:3.0',
366
'FN:John Doe',
367
'TEL:+1234567890',
368
'EMAIL:john@example.com',
369
'URL:https://johndoe.com',
370
'END:VCARD'
371
].join('\n');
372
});
373
374
const contactQR = useQRCode(contactInfo, {
375
errorCorrectionLevel: 'medium',
376
width: 300
377
});
378
379
// WiFi QR code
380
const wifiConfig = computed(() => {
381
const ssid = 'MyWiFi';
382
const password = 'MyPassword';
383
const security = 'WPA';
384
return `WIFI:T:${security};S:${ssid};P:${password};;`;
385
});
386
387
const wifiQR = useQRCode(wifiConfig);
388
389
// Custom styling options
390
const styledQR = useQRCode('Custom styled QR code', {
391
width: 250,
392
margin: 3,
393
color: {
394
dark: '#1a365d', // Dark blue
395
light: '#f7fafc' // Light gray
396
},
397
errorCorrectionLevel: 'high'
398
});
399
400
// Multiple QR codes with different options
401
const qrCodes = [
402
{
403
name: 'Website',
404
text: ref('https://example.com'),
405
options: { width: 150, color: { dark: '#2563eb' } }
406
},
407
{
408
name: 'Email',
409
text: ref('mailto:contact@example.com'),
410
options: { width: 150, color: { dark: '#dc2626' } }
411
},
412
{
413
name: 'Phone',
414
text: ref('tel:+1234567890'),
415
options: { width: 150, color: { dark: '#059669' } }
416
}
417
].map(item => ({
418
...item,
419
qrCode: useQRCode(item.text, item.options)
420
}));
421
422
// Download QR code
423
const downloadQRCode = (dataUrl: string, filename: string) => {
424
const link = document.createElement('a');
425
link.download = filename;
426
link.href = dataUrl;
427
link.click();
428
};
429
```
430
431
**Template Usage Examples:**
432
433
```vue
434
<template>
435
<div class="qr-code-examples">
436
<!-- Basic QR code display -->
437
<div>
438
<h3>Website QR Code</h3>
439
<img :src="qrCode" alt="QR Code" />
440
</div>
441
442
<!-- Dynamic QR code generator -->
443
<div>
444
<h3>Generate QR Code</h3>
445
<input v-model="userInput" placeholder="Enter text or URL" />
446
<div v-if="userInput">
447
<img :src="qrCodeUrl" alt="Generated QR Code" />
448
<button @click="downloadQRCode(qrCodeUrl, 'qrcode.png')">
449
Download QR Code
450
</button>
451
</div>
452
</div>
453
454
<!-- Multiple QR codes -->
455
<div class="qr-grid">
456
<div v-for="item in qrCodes" :key="item.name" class="qr-item">
457
<h4>{{ item.name }}</h4>
458
<img :src="item.qrCode" :alt="`${item.name} QR Code`" />
459
</div>
460
</div>
461
</div>
462
</template>
463
464
<style>
465
.qr-code-examples {
466
display: flex;
467
flex-direction: column;
468
gap: 20px;
469
}
470
471
.qr-grid {
472
display: grid;
473
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
474
gap: 16px;
475
}
476
477
.qr-item {
478
text-align: center;
479
padding: 16px;
480
border: 1px solid #e2e8f0;
481
border-radius: 8px;
482
}
483
484
.qr-item img {
485
max-width: 100%;
486
height: auto;
487
}
488
</style>
489
```