canvasframework 0.5.26 → 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.
- package/components/Card.js +195 -94
- package/package.json +1 -1
package/components/Card.js
CHANGED
|
@@ -8,11 +8,12 @@ import Component from '../core/Component.js';
|
|
|
8
8
|
* @property {number} padding - Padding interne
|
|
9
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'
|
|
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}
|
|
15
|
+
* @property {boolean} autoLayout - Active le layout automatique
|
|
16
|
+
* @property {Map} childPositions - Positions relatives des enfants
|
|
16
17
|
*/
|
|
17
18
|
class Card extends Component {
|
|
18
19
|
/**
|
|
@@ -26,19 +27,22 @@ class Card extends Component {
|
|
|
26
27
|
* @param {string} [options.bgColor='transparent'] - Couleur de fond
|
|
27
28
|
* @param {number} [options.borderRadius=0] - Rayon des coins
|
|
28
29
|
* @param {number} [options.elevation=0] - Niveau d'élévation (0-5)
|
|
29
|
-
* @param {boolean} [options.
|
|
30
|
+
* @param {boolean} [options.autoLayout=true] - Active le layout automatique
|
|
30
31
|
*/
|
|
31
32
|
constructor(framework, options = {}) {
|
|
32
33
|
super(framework, options);
|
|
33
34
|
this.children = [];
|
|
34
35
|
this.padding = options.padding || 0;
|
|
35
|
-
this.gap = options.gap || 0;
|
|
36
|
+
this.gap = options.gap || 0;
|
|
36
37
|
this.direction = options.direction || 'column';
|
|
37
38
|
this.align = options.align || 'start';
|
|
38
39
|
this.bgColor = options.bgColor || 'transparent';
|
|
39
40
|
this.borderRadius = options.borderRadius || 0;
|
|
40
41
|
this.elevation = options.elevation || 0;
|
|
41
|
-
this.
|
|
42
|
+
this.autoLayout = options.autoLayout !== undefined ? options.autoLayout : true;
|
|
43
|
+
|
|
44
|
+
// Stocker les positions relatives des enfants
|
|
45
|
+
this.childPositions = new Map();
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
/**
|
|
@@ -48,7 +52,17 @@ class Card extends Component {
|
|
|
48
52
|
*/
|
|
49
53
|
add(child) {
|
|
50
54
|
this.children.push(child);
|
|
51
|
-
|
|
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
|
+
|
|
52
66
|
return child;
|
|
53
67
|
}
|
|
54
68
|
|
|
@@ -61,7 +75,8 @@ class Card extends Component {
|
|
|
61
75
|
const index = this.children.indexOf(child);
|
|
62
76
|
if (index > -1) {
|
|
63
77
|
this.children.splice(index, 1);
|
|
64
|
-
this.
|
|
78
|
+
this.childPositions.delete(child);
|
|
79
|
+
if (this.autoLayout) this.layout();
|
|
65
80
|
return true;
|
|
66
81
|
}
|
|
67
82
|
return false;
|
|
@@ -72,91 +87,127 @@ class Card extends Component {
|
|
|
72
87
|
*/
|
|
73
88
|
clear() {
|
|
74
89
|
this.children = [];
|
|
75
|
-
this.
|
|
90
|
+
this.childPositions.clear();
|
|
91
|
+
if (this.autoLayout) this.layout();
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
/**
|
|
79
|
-
* Organise les enfants selon le layout
|
|
95
|
+
* Organise les enfants selon le layout
|
|
80
96
|
* @private
|
|
81
97
|
*/
|
|
82
98
|
layout() {
|
|
83
|
-
if (this.children.length === 0) return;
|
|
99
|
+
if (this.children.length === 0 || !this.autoLayout) return;
|
|
84
100
|
|
|
85
|
-
let currentX = this.x + this.padding;
|
|
86
|
-
let currentY = this.y + this.padding;
|
|
87
|
-
|
|
88
101
|
if (this.direction === 'column') {
|
|
102
|
+
let currentY = this.padding;
|
|
103
|
+
|
|
89
104
|
for (let i = 0; i < this.children.length; i++) {
|
|
90
105
|
const child = this.children[i];
|
|
91
106
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
child.y = currentY;
|
|
95
|
-
|
|
96
|
-
// Gérer l'alignement horizontal
|
|
107
|
+
// Calculer la position X selon l'alignement
|
|
108
|
+
let childX = this.padding;
|
|
97
109
|
if (this.align === 'center') {
|
|
98
|
-
|
|
110
|
+
childX = (this.width - child.width) / 2;
|
|
99
111
|
} else if (this.align === 'end') {
|
|
100
|
-
|
|
101
|
-
} else if (this.align === 'stretch') {
|
|
102
|
-
child.x = this.x + this.padding;
|
|
103
|
-
child.width = this.width - (this.padding * 2);
|
|
112
|
+
childX = this.width - child.width - this.padding;
|
|
104
113
|
}
|
|
105
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
|
+
|
|
106
122
|
// Mettre à jour la position Y pour l'enfant suivant
|
|
107
|
-
|
|
108
|
-
currentY += child.height + this.gap;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Ajuster la hauteur automatiquement si autoHeight est activé
|
|
112
|
-
if (this.autoHeight) {
|
|
113
|
-
const totalChildrenHeight = this.children.reduce((sum, child) => sum + child.height, 0);
|
|
114
|
-
const totalGapHeight = this.gap * Math.max(0, this.children.length - 1);
|
|
115
|
-
const neededHeight = totalChildrenHeight + totalGapHeight + (this.padding * 2);
|
|
123
|
+
currentY += child.height;
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (this.onResize) this.onResize(this.width, this.height);
|
|
125
|
+
// Ajouter le gap seulement si ce n'est pas le dernier enfant
|
|
126
|
+
if (i < this.children.length - 1) {
|
|
127
|
+
currentY += this.gap;
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
130
|
} else {
|
|
124
|
-
// Direction 'row'
|
|
131
|
+
// Direction 'row'
|
|
132
|
+
let currentX = this.padding;
|
|
133
|
+
|
|
125
134
|
for (let i = 0; i < this.children.length; i++) {
|
|
126
135
|
const child = this.children[i];
|
|
127
136
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// Gérer l'alignement vertical
|
|
137
|
+
// Calculer la position Y selon l'alignement
|
|
138
|
+
let childY = this.padding;
|
|
132
139
|
if (this.align === 'center') {
|
|
133
|
-
|
|
140
|
+
childY = (this.height - child.height) / 2;
|
|
134
141
|
} else if (this.align === 'end') {
|
|
135
|
-
|
|
136
|
-
} else if (this.align === 'stretch') {
|
|
137
|
-
child.y = this.y + this.padding;
|
|
138
|
-
child.height = this.height - (this.padding * 2);
|
|
142
|
+
childY = this.height - child.height - this.padding;
|
|
139
143
|
}
|
|
140
144
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// Ajuster la largeur automatiquement si autoHeight est activé (pour row)
|
|
146
|
-
if (this.autoHeight) {
|
|
147
|
-
const totalChildrenWidth = this.children.reduce((sum, child) => sum + child.width, 0);
|
|
148
|
-
const totalGapWidth = this.gap * Math.max(0, this.children.length - 1);
|
|
149
|
-
const neededWidth = totalChildrenWidth + totalGapWidth + (this.padding * 2);
|
|
145
|
+
// Positionner l'enfant RELATIVEMENT à la Card
|
|
146
|
+
child.x = this.x + currentX;
|
|
147
|
+
child.y = this.y + childY;
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
// Stocker la position relative
|
|
150
|
+
this.childPositions.set(child, { x: currentX, y: childY });
|
|
151
|
+
|
|
152
|
+
// Mettre à jour la position X pour l'enfant suivant
|
|
153
|
+
currentX += child.width;
|
|
154
|
+
|
|
155
|
+
// Ajouter le gap seulement si ce n'est pas le dernier enfant
|
|
156
|
+
if (i < this.children.length - 1) {
|
|
157
|
+
currentX += this.gap;
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
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
|
+
|
|
160
211
|
/**
|
|
161
212
|
* Génère les paramètres d'ombre selon le niveau d'élévation
|
|
162
213
|
* @param {number} elevation - Niveau d'élévation (0-5)
|
|
@@ -230,7 +281,7 @@ class Card extends Component {
|
|
|
230
281
|
}
|
|
231
282
|
}
|
|
232
283
|
|
|
233
|
-
// Appliquer le clipping
|
|
284
|
+
// Appliquer le clipping si borderRadius > 0
|
|
234
285
|
if (this.borderRadius > 0) {
|
|
235
286
|
ctx.beginPath();
|
|
236
287
|
this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
|
|
@@ -309,41 +360,13 @@ class Card extends Component {
|
|
|
309
360
|
this.setElevation(this.elevation - 1);
|
|
310
361
|
}
|
|
311
362
|
|
|
312
|
-
/**
|
|
313
|
-
* Met à jour la position de la carte (surcharge pour recalculer le layout)
|
|
314
|
-
* @param {number} x - Nouvelle position X
|
|
315
|
-
* @param {number} y - Nouvelle position Y
|
|
316
|
-
*/
|
|
317
|
-
setPosition(x, y) {
|
|
318
|
-
const deltaX = x - this.x;
|
|
319
|
-
const deltaY = y - this.y;
|
|
320
|
-
|
|
321
|
-
super.setPosition(x, y);
|
|
322
|
-
|
|
323
|
-
// Déplacer tous les enfants avec la carte
|
|
324
|
-
for (let child of this.children) {
|
|
325
|
-
child.x += deltaX;
|
|
326
|
-
child.y += deltaY;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Met à jour les dimensions (surcharge pour recalculer le layout)
|
|
332
|
-
* @param {number} width - Nouvelle largeur
|
|
333
|
-
* @param {number} height - Nouvelle hauteur
|
|
334
|
-
*/
|
|
335
|
-
setSize(width, height) {
|
|
336
|
-
super.setSize(width, height);
|
|
337
|
-
this.layout();
|
|
338
|
-
}
|
|
339
|
-
|
|
340
363
|
/**
|
|
341
364
|
* Définit l'espacement entre enfants
|
|
342
365
|
* @param {number} gap - Nouvel espacement
|
|
343
366
|
*/
|
|
344
367
|
setGap(gap) {
|
|
345
368
|
this.gap = Math.max(0, gap);
|
|
346
|
-
this.layout();
|
|
369
|
+
if (this.autoLayout) this.layout();
|
|
347
370
|
}
|
|
348
371
|
|
|
349
372
|
/**
|
|
@@ -352,7 +375,7 @@ class Card extends Component {
|
|
|
352
375
|
*/
|
|
353
376
|
setPadding(padding) {
|
|
354
377
|
this.padding = Math.max(0, padding);
|
|
355
|
-
this.layout();
|
|
378
|
+
if (this.autoLayout) this.layout();
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
/**
|
|
@@ -362,20 +385,98 @@ class Card extends Component {
|
|
|
362
385
|
setDirection(direction) {
|
|
363
386
|
if (direction === 'column' || direction === 'row') {
|
|
364
387
|
this.direction = direction;
|
|
365
|
-
this.layout();
|
|
388
|
+
if (this.autoLayout) this.layout();
|
|
366
389
|
}
|
|
367
390
|
}
|
|
368
391
|
|
|
369
392
|
/**
|
|
370
393
|
* Définit l'alignement
|
|
371
|
-
* @param {string} align - 'start', 'center', 'end'
|
|
394
|
+
* @param {string} align - 'start', 'center', 'end'
|
|
372
395
|
*/
|
|
373
396
|
setAlign(align) {
|
|
374
|
-
if (['start', 'center', 'end'
|
|
397
|
+
if (['start', 'center', 'end'].includes(align)) {
|
|
375
398
|
this.align = align;
|
|
376
|
-
this.layout();
|
|
399
|
+
if (this.autoLayout) this.layout();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Calcule la hauteur totale nécessaire pour contenir tous les enfants
|
|
405
|
+
* @returns {number} Hauteur totale nécessaire
|
|
406
|
+
*/
|
|
407
|
+
getTotalHeight() {
|
|
408
|
+
if (this.children.length === 0) return 0;
|
|
409
|
+
|
|
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;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Calcule la largeur totale nécessaire pour contenir tous les enfants
|
|
420
|
+
* @returns {number} Largeur totale nécessaire
|
|
421
|
+
*/
|
|
422
|
+
getTotalWidth() {
|
|
423
|
+
if (this.children.length === 0) return 0;
|
|
424
|
+
|
|
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;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Ajuste automatiquement la hauteur de la carte pour contenir tous les enfants
|
|
435
|
+
*/
|
|
436
|
+
fitHeight() {
|
|
437
|
+
if (this.direction === 'column') {
|
|
438
|
+
this.height = this.getTotalHeight();
|
|
377
439
|
}
|
|
378
440
|
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Ajuste automatiquement la largeur de la carte pour contenir tous les enfants
|
|
444
|
+
*/
|
|
445
|
+
fitWidth() {
|
|
446
|
+
if (this.direction === 'row') {
|
|
447
|
+
this.width = this.getTotalWidth();
|
|
448
|
+
}
|
|
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
|
+
}
|
|
379
480
|
}
|
|
380
481
|
|
|
381
482
|
export default Card;
|