canvasframework 0.5.27 → 0.5.28

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 (2) hide show
  1. package/components/Card.js +155 -74
  2. package/package.json +1 -1
@@ -6,12 +6,14 @@ import Component from '../core/Component.js';
6
6
  * @extends Component
7
7
  * @property {Component[]} children - Enfants
8
8
  * @property {number} padding - Padding interne
9
- * @property {number} gap - Espacement constant entre enfants SEULEMENT
9
+ * @property {number} gap - Espacement constant entre enfants
10
10
  * @property {string} direction - Direction ('column' ou 'row')
11
- * @property {string} align - Alignement ('start', 'center', 'end', 'stretch')
11
+ * @property {string} align - Alignement ('start', 'center', 'end')
12
12
  * @property {string} bgColor - Couleur de fond
13
13
  * @property {number} borderRadius - Rayon des coins
14
14
  * @property {number} elevation - Niveau d'élévation (ombres)
15
+ * @property {boolean} autoLayout - Active le layout automatique
16
+ * @property {Map} childPositions - Positions relatives des enfants
15
17
  */
16
18
  class Card extends Component {
17
19
  /**
@@ -19,23 +21,28 @@ class Card extends Component {
19
21
  * @param {CanvasFramework} framework - Framework parent
20
22
  * @param {Object} [options={}] - Options de configuration
21
23
  * @param {number} [options.padding=0] - Padding interne
22
- * @param {number} [options.gap=0] - Espacement constant entre enfants SEULEMENT
24
+ * @param {number} [options.gap=0] - Espacement constant entre enfants
23
25
  * @param {string} [options.direction='column'] - Direction
24
26
  * @param {string} [options.align='start'] - Alignement
25
27
  * @param {string} [options.bgColor='transparent'] - Couleur de fond
26
28
  * @param {number} [options.borderRadius=0] - Rayon des coins
27
29
  * @param {number} [options.elevation=0] - Niveau d'élévation (0-5)
30
+ * @param {boolean} [options.autoLayout=true] - Active le layout automatique
28
31
  */
29
32
  constructor(framework, options = {}) {
30
33
  super(framework, options);
31
34
  this.children = [];
32
35
  this.padding = options.padding || 0;
33
- this.gap = options.gap || 0; // Espacement UNIQUEMENT entre enfants
36
+ this.gap = options.gap || 0;
34
37
  this.direction = options.direction || 'column';
35
38
  this.align = options.align || 'start';
36
39
  this.bgColor = options.bgColor || 'transparent';
37
40
  this.borderRadius = options.borderRadius || 0;
38
41
  this.elevation = options.elevation || 0;
42
+ this.autoLayout = options.autoLayout !== undefined ? options.autoLayout : true;
43
+
44
+ // Stocker les positions relatives des enfants
45
+ this.childPositions = new Map();
39
46
  }
40
47
 
41
48
  /**
@@ -45,7 +52,17 @@ class Card extends Component {
45
52
  */
46
53
  add(child) {
47
54
  this.children.push(child);
48
- this.layout();
55
+
56
+ // Si autoLayout est activé, organiser automatiquement
57
+ if (this.autoLayout) {
58
+ this.layout();
59
+ } else {
60
+ // En mode manuel, calculer et stocker la position relative
61
+ const relativeX = child.x - this.x;
62
+ const relativeY = child.y - this.y;
63
+ this.childPositions.set(child, { x: relativeX, y: relativeY });
64
+ }
65
+
49
66
  return child;
50
67
  }
51
68
 
@@ -58,7 +75,8 @@ class Card extends Component {
58
75
  const index = this.children.indexOf(child);
59
76
  if (index > -1) {
60
77
  this.children.splice(index, 1);
61
- this.layout();
78
+ this.childPositions.delete(child);
79
+ if (this.autoLayout) this.layout();
62
80
  return true;
63
81
  }
64
82
  return false;
@@ -69,40 +87,39 @@ class Card extends Component {
69
87
  */
70
88
  clear() {
71
89
  this.children = [];
72
- this.layout();
90
+ this.childPositions.clear();
91
+ if (this.autoLayout) this.layout();
73
92
  }
74
93
 
75
94
  /**
76
- * Organise les enfants selon le layout avec espacement constant
95
+ * Organise les enfants selon le layout
77
96
  * @private
78
97
  */
79
98
  layout() {
80
- if (this.children.length === 0) return;
99
+ if (this.children.length === 0 || !this.autoLayout) return;
81
100
 
82
101
  if (this.direction === 'column') {
83
- let currentY = this.y + this.padding;
102
+ let currentY = this.padding;
84
103
 
85
104
  for (let i = 0; i < this.children.length; i++) {
86
105
  const child = this.children[i];
87
106
 
88
- // Positionner l'enfant sans tenir compte de ses marges internes
89
- child.y = currentY;
90
-
91
- // Gérer l'alignement horizontal
107
+ // Calculer la position X selon l'alignement
108
+ let childX = this.padding;
92
109
  if (this.align === 'center') {
93
- child.x = this.x + (this.width - child.width) / 2;
110
+ childX = (this.width - child.width) / 2;
94
111
  } else if (this.align === 'end') {
95
- child.x = this.x + this.width - child.width - this.padding;
96
- } else if (this.align === 'stretch') {
97
- child.x = this.x + this.padding;
98
- child.width = this.width - (this.padding * 2);
99
- } else {
100
- // Alignement 'start' par défaut
101
- child.x = this.x + this.padding;
112
+ childX = this.width - child.width - this.padding;
102
113
  }
103
114
 
115
+ // Positionner l'enfant RELATIVEMENT à la Card
116
+ child.x = this.x + childX;
117
+ child.y = this.y + currentY;
118
+
119
+ // Stocker la position relative
120
+ this.childPositions.set(child, { x: childX, y: currentY });
121
+
104
122
  // Mettre à jour la position Y pour l'enfant suivant
105
- // UNIQUEMENT avec le gap spécifié, rien d'autre
106
123
  currentY += child.height;
107
124
 
108
125
  // Ajouter le gap seulement si ce n'est pas le dernier enfant
@@ -112,25 +129,26 @@ class Card extends Component {
112
129
  }
113
130
  } else {
114
131
  // Direction 'row'
115
- let currentX = this.x + this.padding;
132
+ let currentX = this.padding;
116
133
 
117
134
  for (let i = 0; i < this.children.length; i++) {
118
135
  const child = this.children[i];
119
136
 
120
- child.x = currentX;
121
-
122
- // Gérer l'alignement vertical
137
+ // Calculer la position Y selon l'alignement
138
+ let childY = this.padding;
123
139
  if (this.align === 'center') {
124
- child.y = this.y + (this.height - child.height) / 2;
140
+ childY = (this.height - child.height) / 2;
125
141
  } else if (this.align === 'end') {
126
- child.y = this.y + this.height - child.height - this.padding;
127
- } else if (this.align === 'stretch') {
128
- child.y = this.y + this.padding;
129
- child.height = this.height - (this.padding * 2);
130
- } else {
131
- child.y = this.y + this.padding;
142
+ childY = this.height - child.height - this.padding;
132
143
  }
133
144
 
145
+ // Positionner l'enfant RELATIVEMENT à la Card
146
+ child.x = this.x + currentX;
147
+ child.y = this.y + childY;
148
+
149
+ // Stocker la position relative
150
+ this.childPositions.set(child, { x: currentX, y: childY });
151
+
134
152
  // Mettre à jour la position X pour l'enfant suivant
135
153
  currentX += child.width;
136
154
 
@@ -142,6 +160,54 @@ class Card extends Component {
142
160
  }
143
161
  }
144
162
 
163
+ /**
164
+ * Met à jour la position de la carte et ajuste les enfants
165
+ * @param {number} x - Nouvelle position X
166
+ * @param {number} y - Nouvelle position Y
167
+ */
168
+ setPosition(x, y) {
169
+ const deltaX = x - this.x;
170
+ const deltaY = y - this.y;
171
+
172
+ super.setPosition(x, y);
173
+
174
+ // Déplacer tous les enfants avec la carte
175
+ for (let child of this.children) {
176
+ child.x += deltaX;
177
+ child.y += deltaY;
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Définit la position d'un enfant dans le système de coordonnées de la Card
183
+ * @param {Component} child - L'enfant à positionner
184
+ * @param {number} relativeX - Position X relative à la Card
185
+ * @param {number} relativeY - Position Y relative à la Card
186
+ */
187
+ setChildPosition(child, relativeX, relativeY) {
188
+ if (this.children.includes(child)) {
189
+ child.x = this.x + relativeX;
190
+ child.y = this.y + relativeY;
191
+ this.childPositions.set(child, { x: relativeX, y: relativeY });
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Active/désactive le layout automatique
197
+ * @param {boolean} enabled - True pour activer le layout automatique
198
+ */
199
+ setAutoLayout(enabled) {
200
+ this.autoLayout = enabled;
201
+ if (enabled) this.layout();
202
+ }
203
+
204
+ /**
205
+ * Force un recalcul du layout
206
+ */
207
+ updateLayout() {
208
+ this.layout();
209
+ }
210
+
145
211
  /**
146
212
  * Génère les paramètres d'ombre selon le niveau d'élévation
147
213
  * @param {number} elevation - Niveau d'élévation (0-5)
@@ -215,6 +281,13 @@ class Card extends Component {
215
281
  }
216
282
  }
217
283
 
284
+ // Appliquer le clipping si borderRadius > 0
285
+ if (this.borderRadius > 0) {
286
+ ctx.beginPath();
287
+ this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
288
+ ctx.clip();
289
+ }
290
+
218
291
  // Dessiner les enfants
219
292
  for (let child of this.children) {
220
293
  if (child.visible) child.draw(ctx);
@@ -287,41 +360,13 @@ class Card extends Component {
287
360
  this.setElevation(this.elevation - 1);
288
361
  }
289
362
 
290
- /**
291
- * Met à jour la position de la carte (surcharge pour recalculer le layout)
292
- * @param {number} x - Nouvelle position X
293
- * @param {number} y - Nouvelle position Y
294
- */
295
- setPosition(x, y) {
296
- const deltaX = x - this.x;
297
- const deltaY = y - this.y;
298
-
299
- super.setPosition(x, y);
300
-
301
- // Déplacer tous les enfants avec la carte
302
- for (let child of this.children) {
303
- child.x += deltaX;
304
- child.y += deltaY;
305
- }
306
- }
307
-
308
- /**
309
- * Met à jour les dimensions (surcharge pour recalculer le layout)
310
- * @param {number} width - Nouvelle largeur
311
- * @param {number} height - Nouvelle hauteur
312
- */
313
- setSize(width, height) {
314
- super.setSize(width, height);
315
- this.layout();
316
- }
317
-
318
363
  /**
319
364
  * Définit l'espacement entre enfants
320
365
  * @param {number} gap - Nouvel espacement
321
366
  */
322
367
  setGap(gap) {
323
368
  this.gap = Math.max(0, gap);
324
- this.layout();
369
+ if (this.autoLayout) this.layout();
325
370
  }
326
371
 
327
372
  /**
@@ -330,7 +375,7 @@ class Card extends Component {
330
375
  */
331
376
  setPadding(padding) {
332
377
  this.padding = Math.max(0, padding);
333
- this.layout();
378
+ if (this.autoLayout) this.layout();
334
379
  }
335
380
 
336
381
  /**
@@ -340,18 +385,18 @@ class Card extends Component {
340
385
  setDirection(direction) {
341
386
  if (direction === 'column' || direction === 'row') {
342
387
  this.direction = direction;
343
- this.layout();
388
+ if (this.autoLayout) this.layout();
344
389
  }
345
390
  }
346
391
 
347
392
  /**
348
393
  * Définit l'alignement
349
- * @param {string} align - 'start', 'center', 'end' ou 'stretch'
394
+ * @param {string} align - 'start', 'center', 'end'
350
395
  */
351
396
  setAlign(align) {
352
- if (['start', 'center', 'end', 'stretch'].includes(align)) {
397
+ if (['start', 'center', 'end'].includes(align)) {
353
398
  this.align = align;
354
- this.layout();
399
+ if (this.autoLayout) this.layout();
355
400
  }
356
401
  }
357
402
 
@@ -362,9 +407,12 @@ class Card extends Component {
362
407
  getTotalHeight() {
363
408
  if (this.children.length === 0) return 0;
364
409
 
365
- const totalChildrenHeight = this.children.reduce((sum, child) => sum + child.height, 0);
366
- const totalGapHeight = this.gap * Math.max(0, this.children.length - 1);
367
- return totalChildrenHeight + totalGapHeight + (this.padding * 2);
410
+ if (this.direction === 'column') {
411
+ const totalChildrenHeight = this.children.reduce((sum, child) => sum + child.height, 0);
412
+ const totalGapHeight = this.gap * Math.max(0, this.children.length - 1);
413
+ return totalChildrenHeight + totalGapHeight + (this.padding * 2);
414
+ }
415
+ return this.height;
368
416
  }
369
417
 
370
418
  /**
@@ -374,9 +422,12 @@ class Card extends Component {
374
422
  getTotalWidth() {
375
423
  if (this.children.length === 0) return 0;
376
424
 
377
- const totalChildrenWidth = this.children.reduce((sum, child) => sum + child.width, 0);
378
- const totalGapWidth = this.gap * Math.max(0, this.children.length - 1);
379
- return totalChildrenWidth + totalGapWidth + (this.padding * 2);
425
+ if (this.direction === 'row') {
426
+ const totalChildrenWidth = this.children.reduce((sum, child) => sum + child.width, 0);
427
+ const totalGapWidth = this.gap * Math.max(0, this.children.length - 1);
428
+ return totalChildrenWidth + totalGapWidth + (this.padding * 2);
429
+ }
430
+ return this.width;
380
431
  }
381
432
 
382
433
  /**
@@ -396,6 +447,36 @@ class Card extends Component {
396
447
  this.width = this.getTotalWidth();
397
448
  }
398
449
  }
450
+
451
+ /**
452
+ * Ajuste automatiquement les dimensions de la carte pour contenir tous les enfants
453
+ */
454
+ fitSize() {
455
+ if (this.direction === 'column') {
456
+ this.height = this.getTotalHeight();
457
+ } else if (this.direction === 'row') {
458
+ this.width = this.getTotalWidth();
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Met à jour les dimensions et relayout si autoLayout est activé
464
+ * @param {number} width - Nouvelle largeur
465
+ * @param {number} height - Nouvelle hauteur
466
+ */
467
+ setSize(width, height) {
468
+ super.setSize(width, height);
469
+ if (this.autoLayout) this.layout();
470
+ }
471
+
472
+ /**
473
+ * Obtient la position relative d'un enfant
474
+ * @param {Component} child - L'enfant
475
+ * @returns {Object|null} Position relative {x, y} ou null si non trouvé
476
+ */
477
+ getChildPosition(child) {
478
+ return this.childPositions.get(child) || null;
479
+ }
399
480
  }
400
481
 
401
482
  export default Card;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.5.27",
3
+ "version": "0.5.28",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/beyons/CanvasFramework.git"