canvasframework 0.5.16 → 0.5.18

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.
Files changed (112) hide show
  1. package/dist/canvasframework.js +2 -0
  2. package/dist/canvasframework.js.LICENSE.txt +1 -0
  3. package/package.json +18 -17
  4. package/components/Accordion.js +0 -265
  5. package/components/AndroidDatePickerDialog.js +0 -406
  6. package/components/AppBar.js +0 -398
  7. package/components/AudioPlayer.js +0 -611
  8. package/components/Avatar.js +0 -202
  9. package/components/Banner.js +0 -342
  10. package/components/BottomNavigationBar.js +0 -433
  11. package/components/BottomSheet.js +0 -234
  12. package/components/Button.js +0 -360
  13. package/components/Camera.js +0 -644
  14. package/components/Card.js +0 -193
  15. package/components/Chart.js +0 -700
  16. package/components/Checkbox.js +0 -166
  17. package/components/Chip.js +0 -212
  18. package/components/CircularProgress.js +0 -327
  19. package/components/ContextMenu.js +0 -116
  20. package/components/DatePicker.js +0 -298
  21. package/components/Dialog.js +0 -337
  22. package/components/Divider.js +0 -125
  23. package/components/Drawer.js +0 -276
  24. package/components/FAB.js +0 -270
  25. package/components/FileUpload.js +0 -315
  26. package/components/FloatedCamera.js +0 -644
  27. package/components/IOSDatePickerWheel.js +0 -430
  28. package/components/ImageCarousel.js +0 -219
  29. package/components/ImageComponent.js +0 -223
  30. package/components/Input.js +0 -831
  31. package/components/InputDatalist.js +0 -723
  32. package/components/InputTags.js +0 -624
  33. package/components/List.js +0 -95
  34. package/components/ListItem.js +0 -269
  35. package/components/Modal.js +0 -364
  36. package/components/MorphingFAB.js +0 -428
  37. package/components/MultiSelectDialog.js +0 -206
  38. package/components/NumberInput.js +0 -271
  39. package/components/PasswordInput.js +0 -462
  40. package/components/ProgressBar.js +0 -88
  41. package/components/QRCodeReader.js +0 -539
  42. package/components/RadioButton.js +0 -151
  43. package/components/SearchInput.js +0 -315
  44. package/components/SegmentedControl.js +0 -357
  45. package/components/Select.js +0 -199
  46. package/components/SelectDialog.js +0 -255
  47. package/components/Slider.js +0 -113
  48. package/components/SliverAppBar.js +0 -139
  49. package/components/Snackbar.js +0 -243
  50. package/components/SpeedDialFAB.js +0 -397
  51. package/components/Stepper.js +0 -281
  52. package/components/SwipeableListItem.js +0 -327
  53. package/components/Switch.js +0 -147
  54. package/components/Table.js +0 -492
  55. package/components/Tabs.js +0 -423
  56. package/components/Text.js +0 -141
  57. package/components/TextField.js +0 -151
  58. package/components/TimePicker.js +0 -934
  59. package/components/Toast.js +0 -236
  60. package/components/TreeView.js +0 -420
  61. package/components/Video.js +0 -397
  62. package/components/View.js +0 -140
  63. package/components/VirtualList.js +0 -120
  64. package/core/CanvasFramework.js +0 -3034
  65. package/core/Component.js +0 -243
  66. package/core/ThemeManager.js +0 -358
  67. package/core/UIBuilder.js +0 -267
  68. package/core/WebGLCanvasAdapter.js +0 -782
  69. package/features/Column.js +0 -43
  70. package/features/Grid.js +0 -47
  71. package/features/LayoutComponent.js +0 -43
  72. package/features/OpenStreetMap.js +0 -310
  73. package/features/Positioned.js +0 -33
  74. package/features/PullToRefresh.js +0 -328
  75. package/features/Row.js +0 -40
  76. package/features/SignaturePad.js +0 -257
  77. package/features/Skeleton.js +0 -193
  78. package/features/Stack.js +0 -21
  79. package/index.js +0 -119
  80. package/manager/AccessibilityManager.js +0 -107
  81. package/manager/ErrorHandler.js +0 -59
  82. package/manager/FeatureFlags.js +0 -60
  83. package/manager/MemoryManager.js +0 -107
  84. package/manager/PerformanceMonitor.js +0 -84
  85. package/manager/SecurityManager.js +0 -54
  86. package/utils/AnimationEngine.js +0 -734
  87. package/utils/CryptoManager.js +0 -303
  88. package/utils/DataStore.js +0 -403
  89. package/utils/DevTools.js +0 -1618
  90. package/utils/DevToolsConsole.js +0 -201
  91. package/utils/EventBus.js +0 -407
  92. package/utils/FetchClient.js +0 -74
  93. package/utils/FirebaseAuth.js +0 -653
  94. package/utils/FirebaseCore.js +0 -246
  95. package/utils/FirebaseFirestore.js +0 -581
  96. package/utils/FirebaseFunctions.js +0 -97
  97. package/utils/FirebaseRealtimeDB.js +0 -498
  98. package/utils/FirebaseStorage.js +0 -612
  99. package/utils/FormValidator.js +0 -355
  100. package/utils/GeoLocationService.js +0 -62
  101. package/utils/I18n.js +0 -207
  102. package/utils/IndexedDBManager.js +0 -273
  103. package/utils/InspectionOverlay.js +0 -308
  104. package/utils/NotificationManager.js +0 -60
  105. package/utils/OfflineSyncManager.js +0 -342
  106. package/utils/PayPalPayment.js +0 -678
  107. package/utils/QueryBuilder.js +0 -478
  108. package/utils/SafeArea.js +0 -64
  109. package/utils/SecureStorage.js +0 -289
  110. package/utils/StateManager.js +0 -207
  111. package/utils/StripePayment.js +0 -552
  112. package/utils/WebSocketClient.js +0 -66
@@ -1,397 +0,0 @@
1
- import Component from '../core/Component.js';
2
- /**
3
- * Lecteur vidéo
4
- * @class
5
- * @extends Component
6
- * @property {string} src - URL de la vidéo
7
- * @property {string} poster - URL de l'image d'affiche
8
- * @property {boolean} playing - En cours de lecture
9
- * @property {string} platform - Plateforme
10
- * @property {boolean} showControls - Afficher les contrôles
11
- * @property {number|null} controlsTimeout - Timeout des contrôles
12
- * @property {number} currentTime - Temps actuel
13
- * @property {number} duration - Durée totale
14
- * @property {number} progress - Progression (0-100)
15
- * @property {number} volume - Volume (0-1)
16
- * @property {boolean} showVolume - Afficher le contrôle de volume
17
- * @property {boolean} fullscreen - Plein écran
18
- * @property {boolean} loaded - Vidéo chargée
19
- * @property {HTMLVideoElement} videoElement - Élément vidéo HTML
20
- * @property {number} controlsHeight - Hauteur des contrôles
21
- * @property {number} volumeHeight - Hauteur du contrôle de volume
22
- * @property {Function} onPlay - Callback à la lecture
23
- * @property {Function} onPause - Callback à la pause
24
- * @property {Function} onEnded - Callback à la fin
25
- * @property {Function} onFullscreen - Callback au plein écran
26
- */
27
- class Video extends Component {
28
- /**
29
- * Crée une instance de Video
30
- * @param {CanvasFramework} framework - Framework parent
31
- * @param {Object} [options={}] - Options de configuration
32
- * @param {string} [options.src=''] - URL de la vidéo
33
- * @param {string} [options.poster=''] - URL de l'image d'affiche
34
- * @param {boolean} [options.playing=false] - Lecture initiale
35
- * @param {boolean} [options.showControls=true] - Afficher les contrôles
36
- * @param {Function} [options.onPlay] - Callback à la lecture
37
- * @param {Function} [options.onPause] - Callback à la pause
38
- * @param {Function} [options.onEnded] - Callback à la fin
39
- * @param {Function} [options.onFullscreen] - Callback au plein écran
40
- */
41
- constructor(framework, options = {}) {
42
- super(framework, options);
43
- this.src = options.src || '';
44
- this.poster = options.poster || '';
45
- this.playing = false;
46
- this.platform = framework.platform;
47
- this.showControls = true;
48
- this.controlsTimeout = null;
49
- this.currentTime = 0;
50
- this.duration = 0;
51
- this.progress = 0;
52
- this.volume = 1;
53
- this.showVolume = false;
54
- this.fullscreen = false;
55
- this.loaded = false;
56
-
57
- // Éléments de contrôle
58
- this.controlsHeight = 50;
59
- this.volumeHeight = 100;
60
-
61
- // Créer l'élément vidéo HTML5
62
- this.videoElement = document.createElement('video');
63
- this.videoElement.style.position = 'fixed';
64
- this.videoElement.style.left = '-9999px'; // Caché
65
- this.videoElement.style.top = '-9999px';
66
- this.videoElement.style.width = '0';
67
- this.videoElement.style.height = '0';
68
- this.videoElement.src = this.src;
69
- this.videoElement.poster = this.poster;
70
- this.videoElement.preload = 'auto';
71
- this.videoElement.crossOrigin = 'anonymous'; // Important pour les vidéos externes
72
- this.videoElement.controls = false; // Nous gérons nos propres contrôles
73
-
74
- document.body.appendChild(this.videoElement);
75
-
76
- // Événements de la vidéo
77
- this.videoElement.addEventListener('loadedmetadata', () => {
78
- this.duration = this.videoElement.duration;
79
- this.loaded = true;
80
- });
81
-
82
- this.videoElement.addEventListener('timeupdate', () => {
83
- this.currentTime = this.videoElement.currentTime;
84
- this.progress = (this.currentTime / this.duration) * 100;
85
- });
86
-
87
- this.videoElement.addEventListener('ended', () => {
88
- this.playing = false;
89
- if (this.onEnded) this.onEnded();
90
- });
91
-
92
- this.videoElement.addEventListener('play', () => {
93
- this.playing = true;
94
- if (this.onPlay) this.onPlay();
95
- });
96
-
97
- this.videoElement.addEventListener('pause', () => {
98
- this.playing = false;
99
- if (this.onPause) this.onPause();
100
- });
101
-
102
- // Événements
103
- this.onPlay = options.onPlay;
104
- this.onPause = options.onPause;
105
- this.onEnded = options.onEnded;
106
- this.onFullscreen = options.onFullscreen;
107
-
108
- // Définir onPress pour les contrôles
109
- this.onPress = this.handlePress.bind(this);
110
- this.onMove = this.handleMove.bind(this);
111
- }
112
-
113
- /**
114
- * Démarre la lecture
115
- */
116
- play() {
117
- if (this.videoElement) {
118
- this.videoElement.play();
119
- this.playing = true;
120
- this.showControlsTemporarily();
121
- }
122
- }
123
-
124
- /**
125
- * Met en pause
126
- */
127
- pause() {
128
- if (this.videoElement) {
129
- this.videoElement.pause();
130
- this.playing = false;
131
- this.showControlsTemporarily();
132
- }
133
- }
134
-
135
- /**
136
- * Alterne lecture/pause
137
- */
138
- togglePlay() {
139
- if (this.playing) {
140
- this.pause();
141
- } else {
142
- this.play();
143
- }
144
- }
145
-
146
- /**
147
- * Affiche temporairement les contrôles
148
- * @private
149
- */
150
- showControlsTemporarily() {
151
- this.showControls = true;
152
- clearTimeout(this.controlsTimeout);
153
- this.controlsTimeout = setTimeout(() => {
154
- if (this.playing) {
155
- this.showControls = false;
156
- }
157
- }, 3000);
158
- }
159
-
160
- /**
161
- * Gère la pression (clic)
162
- * @param {number} x - Coordonnée X
163
- * @param {number} y - Coordonnée Y
164
- * @private
165
- */
166
- handlePress(x, y) {
167
- const adjustedY = y - this.framework.scrollOffset;
168
-
169
- // Montrer les contrôles
170
- this.showControls = true;
171
- this.showControlsTemporarily();
172
-
173
- // Bouton play/pause central
174
- const centerX = this.x + this.width / 2;
175
- const centerY = this.y + this.height / 2;
176
-
177
- if (x >= centerX - 30 && x <= centerX + 30 &&
178
- adjustedY >= centerY - 30 && adjustedY <= centerY + 30) {
179
- this.togglePlay();
180
- return;
181
- }
182
-
183
- // Barre de progression
184
- if (this.showControls && this.loaded) {
185
- const progressBarY = this.y + this.height - 30;
186
- if (adjustedY >= progressBarY && adjustedY <= progressBarY + 10) {
187
- const clickX = x - this.x;
188
- this.progress = (clickX / this.width) * 100;
189
- this.currentTime = (this.duration * this.progress) / 100;
190
- if (this.videoElement) {
191
- this.videoElement.currentTime = this.currentTime;
192
- }
193
- return;
194
- }
195
- }
196
-
197
- // Bouton plein écran
198
- const fullscreenX = this.x + this.width - 40;
199
- const fullscreenY = this.y + this.height - 40;
200
-
201
- if (x >= fullscreenX && x <= fullscreenX + 30 &&
202
- adjustedY >= fullscreenY && adjustedY <= fullscreenY + 30) {
203
- this.toggleFullscreen();
204
- return;
205
- }
206
- }
207
-
208
- /**
209
- * Gère le mouvement
210
- * @param {number} x - Coordonnée X
211
- * @param {number} y - Coordonnée Y
212
- * @private
213
- */
214
- handleMove(x, y) {
215
- // Pour des interactions supplémentaires
216
- }
217
-
218
- /**
219
- * Alterne le plein écran
220
- */
221
- toggleFullscreen() {
222
- if (!document.fullscreenElement && this.videoElement.requestFullscreen) {
223
- this.videoElement.requestFullscreen();
224
- this.fullscreen = true;
225
- if (this.onFullscreen) this.onFullscreen(true);
226
- } else if (document.exitFullscreen) {
227
- document.exitFullscreen();
228
- this.fullscreen = false;
229
- if (this.onFullscreen) this.onFullscreen(false);
230
- }
231
- }
232
-
233
- /**
234
- * Dessine le lecteur vidéo
235
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
236
- */
237
- draw(ctx) {
238
- ctx.save();
239
-
240
- try {
241
- // Dessiner la vidéo sur le canvas
242
- if (this.loaded && this.videoElement.readyState >= 2) {
243
- ctx.drawImage(this.videoElement, this.x, this.y, this.width, this.height);
244
- } else {
245
- // Affichage de chargement
246
- ctx.fillStyle = '#000000';
247
- ctx.fillRect(this.x, this.y, this.width, this.height);
248
-
249
- ctx.fillStyle = '#FFFFFF';
250
- ctx.font = '16px Arial';
251
- ctx.textAlign = 'center';
252
- ctx.textBaseline = 'middle';
253
- ctx.fillText('Chargement de la vidéo...',
254
- this.x + this.width/2, this.y + this.height/2);
255
- }
256
- } catch (error) {
257
- // En cas d'erreur CORS ou autre
258
- ctx.fillStyle = '#000000';
259
- ctx.fillRect(this.x, this.y, this.width, this.height);
260
-
261
- ctx.fillStyle = '#FFFFFF';
262
- ctx.font = '14px Arial';
263
- ctx.textAlign = 'center';
264
- ctx.textBaseline = 'middle';
265
- ctx.fillText('Vidéo: ' + (this.src.substring(0, 30) + '...'),
266
- this.x + this.width/2, this.y + this.height/2 - 10);
267
- ctx.fillText('Cliquez pour lire',
268
- this.x + this.width/2, this.y + this.height/2 + 10);
269
- }
270
-
271
- // Overlay sombre quand en pause
272
- if (!this.playing || this.showControls) {
273
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
274
- ctx.fillRect(this.x, this.y, this.width, this.height);
275
- }
276
-
277
- // Bouton play/pause au centre (quand pause ou contrôles visibles)
278
- if (!this.playing || this.showControls) {
279
- const centerX = this.x + this.width / 2;
280
- const centerY = this.y + this.height / 2;
281
-
282
- // Fond rond pour le bouton
283
- ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
284
- ctx.beginPath();
285
- ctx.arc(centerX, centerY, 30, 0, Math.PI * 2);
286
- ctx.fill();
287
-
288
- // Icône play/pause
289
- ctx.fillStyle = '#FFFFFF';
290
- if (this.playing) {
291
- // Icône pause
292
- ctx.fillRect(centerX - 8, centerY - 15, 6, 30);
293
- ctx.fillRect(centerX + 2, centerY - 15, 6, 30);
294
- } else {
295
- // Icône play (triangle)
296
- ctx.beginPath();
297
- ctx.moveTo(centerX - 5, centerY - 15);
298
- ctx.lineTo(centerX - 5, centerY + 15);
299
- ctx.lineTo(centerX + 20, centerY);
300
- ctx.closePath();
301
- ctx.fill();
302
- }
303
- }
304
-
305
- // Contrôles en bas
306
- if (this.showControls && this.loaded) {
307
- // Overlay pour les contrôles
308
- ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
309
- ctx.fillRect(this.x, this.y + this.height - this.controlsHeight,
310
- this.width, this.controlsHeight);
311
-
312
- // Barre de progression
313
- const progressX = this.x + 10;
314
- const progressY = this.y + this.height - 25;
315
- const progressWidth = this.width - 60; // Réduit pour laisser place au bouton plein écran
316
-
317
- // Fond de la barre
318
- ctx.fillStyle = '#555555';
319
- ctx.fillRect(progressX, progressY, progressWidth, 4);
320
-
321
- // Progression actuelle
322
- ctx.fillStyle = '#FF0000';
323
- const currentProgressWidth = (progressWidth * this.progress) / 100;
324
- ctx.fillRect(progressX, progressY, currentProgressWidth, 4);
325
-
326
- // Curseur de progression
327
- const thumbX = progressX + currentProgressWidth;
328
- ctx.fillStyle = '#FFFFFF';
329
- ctx.beginPath();
330
- ctx.arc(thumbX, progressY + 2, 6, 0, Math.PI * 2);
331
- ctx.fill();
332
-
333
- // Temps
334
- const currentTimeStr = this.formatTime(this.currentTime);
335
- const totalTimeStr = this.formatTime(this.duration);
336
-
337
- ctx.fillStyle = '#FFFFFF';
338
- ctx.font = '12px Arial';
339
- ctx.textAlign = 'left';
340
- ctx.fillText(currentTimeStr, this.x + 10, this.y + this.height - 35);
341
-
342
- ctx.textAlign = 'right';
343
- ctx.fillText(totalTimeStr, this.x + progressWidth + 10, this.y + this.height - 35);
344
-
345
- // Bouton plein écran
346
- const fullscreenX = this.x + this.width - 40;
347
- const fullscreenY = this.y + this.height - 40;
348
-
349
- ctx.strokeStyle = '#FFFFFF';
350
- ctx.lineWidth = 2;
351
- ctx.strokeRect(fullscreenX, fullscreenY, 20, 20);
352
- ctx.beginPath();
353
- ctx.moveTo(fullscreenX + 5, fullscreenY + 5);
354
- ctx.lineTo(fullscreenX + 5, fullscreenY + 15);
355
- ctx.lineTo(fullscreenX + 15, fullscreenY + 15);
356
- ctx.lineTo(fullscreenX + 15, fullscreenY + 5);
357
- ctx.stroke();
358
- }
359
-
360
- ctx.restore();
361
- }
362
-
363
- /**
364
- * Formate un temps en minutes:secondes
365
- * @param {number} seconds - Secondes
366
- * @returns {string} Temps formaté
367
- * @private
368
- */
369
- formatTime(seconds) {
370
- const mins = Math.floor(seconds / 60);
371
- const secs = Math.floor(seconds % 60);
372
- return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
373
- }
374
-
375
- /**
376
- * Vérifie si un point est dans les limites
377
- * @param {number} x - Coordonnée X
378
- * @param {number} y - Coordonnée Y
379
- * @returns {boolean} True si le point est dans le lecteur
380
- */
381
- isPointInside(x, y) {
382
- // Le VideoPlayer est cliquable pour les contrôles
383
- return x >= this.x && x <= this.x + this.width &&
384
- y >= this.y && y <= this.y + this.height;
385
- }
386
-
387
- /**
388
- * Nettoie l'élément vidéo du DOM
389
- */
390
- remove() {
391
- if (this.videoElement && this.videoElement.parentNode) {
392
- this.videoElement.parentNode.removeChild(this.videoElement);
393
- }
394
- }
395
- }
396
-
397
- export default Video;
@@ -1,140 +0,0 @@
1
- import Component from '../core/Component.js';
2
- /**
3
- * Container avec système de layout
4
- * @class
5
- * @extends Component
6
- * @property {Component[]} children - Enfants
7
- * @property {number} padding - Padding interne
8
- * @property {number} gap - Espacement entre enfants
9
- * @property {string} direction - Direction ('column' ou 'row')
10
- * @property {string} align - Alignement ('start', 'center', 'end')
11
- * @property {string} bgColor - Couleur de fond
12
- * @property {number} borderRadius - Rayon des coins
13
- */
14
- class View extends Component {
15
- /**
16
- * Crée une instance de View
17
- * @param {CanvasFramework} framework - Framework parent
18
- * @param {Object} [options={}] - Options de configuration
19
- * @param {number} [options.padding=0] - Padding interne
20
- * @param {number} [options.gap=0] - Espacement entre enfants
21
- * @param {string} [options.direction='column'] - Direction
22
- * @param {string} [options.align='start'] - Alignement
23
- * @param {string} [options.bgColor='transparent'] - Couleur de fond
24
- * @param {number} [options.borderRadius=0] - Rayon des coins
25
- */
26
- constructor(framework, options = {}) {
27
- super(framework, options);
28
- this.children = [];
29
- this.padding = options.padding || 0;
30
- this.gap = options.gap || 0;
31
- this.direction = options.direction || 'column'; // 'column' ou 'row'
32
- this.align = options.align || 'start'; // 'start', 'center', 'end'
33
- this.bgColor = options.bgColor || 'transparent';
34
- this.borderRadius = options.borderRadius || 0;
35
- }
36
-
37
- /**
38
- * Ajoute un enfant
39
- * @param {Component} child - Composant enfant
40
- * @returns {Component} L'enfant ajouté
41
- */
42
- add(child) {
43
- this.children.push(child);
44
- this.layout();
45
- return child;
46
- }
47
-
48
- /**
49
- * Organise les enfants selon le layout
50
- * @private
51
- */
52
- layout() {
53
- let currentX = this.x + this.padding;
54
- let currentY = this.y + this.padding;
55
-
56
- for (let child of this.children) {
57
- if (this.direction === 'column') {
58
- child.x = currentX;
59
- child.y = currentY;
60
- if (this.align === 'center') {
61
- child.x = this.x + (this.width - child.width) / 2;
62
- } else if (this.align === 'end') {
63
- child.x = this.x + this.width - child.width - this.padding;
64
- }
65
- currentY += child.height + this.gap;
66
- } else {
67
- child.x = currentX;
68
- child.y = currentY;
69
- if (this.align === 'center') {
70
- child.y = this.y + (this.height - child.height) / 2;
71
- } else if (this.align === 'end') {
72
- child.y = this.y + this.height - child.height - this.padding;
73
- }
74
- currentX += child.width + this.gap;
75
- }
76
- }
77
- }
78
-
79
- /**
80
- * Dessine la vue et ses enfants
81
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
82
- */
83
- draw(ctx) {
84
- ctx.save();
85
-
86
- if (this.bgColor !== 'transparent') {
87
- ctx.fillStyle = this.bgColor;
88
- if (this.borderRadius > 0) {
89
- ctx.beginPath();
90
- this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
91
- ctx.fill();
92
- } else {
93
- ctx.fillRect(this.x, this.y, this.width, this.height);
94
- }
95
- }
96
-
97
- for (let child of this.children) {
98
- if (child.visible) child.draw(ctx);
99
- }
100
-
101
- ctx.restore();
102
- }
103
-
104
- /**
105
- * Dessine un rectangle avec coins arrondis
106
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
107
- * @param {number} x - Position X
108
- * @param {number} y - Position Y
109
- * @param {number} width - Largeur
110
- * @param {number} height - Hauteur
111
- * @param {number} radius - Rayon des coins
112
- * @private
113
- */
114
- roundRect(ctx, x, y, width, height, radius) {
115
- ctx.moveTo(x + radius, y);
116
- ctx.lineTo(x + width - radius, y);
117
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
118
- ctx.lineTo(x + width, y + height - radius);
119
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
120
- ctx.lineTo(x + radius, y + height);
121
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
122
- ctx.lineTo(x, y + radius);
123
- ctx.quadraticCurveTo(x, y, x + radius, y);
124
- }
125
-
126
- /**
127
- * Vérifie si un point est dans les limites
128
- * @param {number} x - Coordonnée X
129
- * @param {number} y - Coordonnée Y
130
- * @returns {boolean} True si le point est dans la vue
131
- */
132
- isPointInside(x, y) {
133
- return x >= this.x &&
134
- x <= this.x + this.width &&
135
- y >= this.y &&
136
- y <= this.y + this.height;
137
- }
138
- }
139
-
140
- export default View;
@@ -1,120 +0,0 @@
1
- import Component from '../core/Component.js';
2
- import ListItem from '../components/ListItem.js';
3
-
4
- /**
5
- * Virtual List : optimise le rendu pour les longues listes
6
- * @class
7
- * @extends Component
8
- */
9
- class VirtualList extends Component {
10
- constructor(framework, options = {}) {
11
- super(framework, options);
12
-
13
- this.allItemsData = []; // Stocke toutes les données des items (mais pas tous les objets)
14
- this.visibleItems = []; // Liste des ListItem réellement créés/dessinés
15
- this.itemHeight = options.itemHeight || 56;
16
- this.onItemClick = options.onItemClick;
17
- this.y = options.y || 0;
18
-
19
- this.viewportHeight = options.height || framework.height; // Hauteur visible
20
- this.scrollOffset = 0; // Position de scroll
21
- }
22
-
23
- /**
24
- * Ajoute un item (seule la data est stockée)
25
- * @param {Object} itemOptions
26
- */
27
- addItem(itemOptions) {
28
- this.allItemsData.push(itemOptions);
29
- this.updateVisibleItems();
30
- }
31
-
32
- /**
33
- * Supprime tous les items
34
- */
35
- clear() {
36
- for (let item of this.visibleItems) {
37
- this.framework.remove(item);
38
- }
39
- this.allItemsData = [];
40
- this.visibleItems = [];
41
- this.height = 0;
42
- }
43
-
44
- /**
45
- * Met à jour la liste des items visibles selon scrollOffset
46
- */
47
- updateVisibleItems() {
48
- const firstIndex = Math.floor(this.scrollOffset / this.itemHeight);
49
- const lastIndex = Math.min(this.allItemsData.length - 1, Math.ceil((this.scrollOffset + this.viewportHeight) / this.itemHeight));
50
-
51
- const newVisibleItems = [];
52
-
53
- for (let i = firstIndex; i <= lastIndex; i++) {
54
- let item = this.visibleItems.find(v => v.__virtualIndex === i);
55
- if (!item) {
56
- // Crée un nouvel item si pas existant
57
- const data = this.allItemsData[i];
58
- item = new ListItem(this.framework, {
59
- ...data,
60
- x: this.x,
61
- y: this.y + i * this.itemHeight - this.scrollOffset,
62
- width: this.width,
63
- height: this.itemHeight,
64
- onClick: () => {
65
- if (this.onItemClick) this.onItemClick(i, data);
66
- if (data.onClick) data.onClick();
67
- }
68
- });
69
- item.__virtualIndex = i;
70
- this.framework.add(item);
71
- } else {
72
- // Met à jour la position Y si déjà existant
73
- item.y = this.y + i * this.itemHeight - this.scrollOffset;
74
- }
75
- newVisibleItems.push(item);
76
- }
77
-
78
- // Supprime les items qui ne sont plus visibles
79
- for (let item of this.visibleItems) {
80
- if (!newVisibleItems.includes(item)) {
81
- this.framework.remove(item);
82
- }
83
- }
84
-
85
- this.visibleItems = newVisibleItems;
86
- this.height = this.allItemsData.length * this.itemHeight;
87
- }
88
-
89
- /**
90
- * Scroll la liste
91
- * @param {number} deltaY
92
- */
93
- scroll(deltaY) {
94
- this.scrollOffset += deltaY;
95
- if (this.scrollOffset < 0) this.scrollOffset = 0;
96
- const maxScroll = Math.max(0, this.height - this.viewportHeight);
97
- if (this.scrollOffset > maxScroll) this.scrollOffset = maxScroll;
98
-
99
- this.updateVisibleItems();
100
- }
101
-
102
- /**
103
- * Dessine les items visibles
104
- * @param {CanvasRenderingContext2D} ctx
105
- */
106
- draw(ctx) {
107
- for (let item of this.visibleItems) {
108
- item.draw(ctx);
109
- }
110
- }
111
-
112
- /**
113
- * Toujours false : les ListItems gèrent leurs clics
114
- */
115
- isPointInside() {
116
- return false;
117
- }
118
- }
119
-
120
- export default VirtualList;