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.
- package/components/Card.js +155 -74
- package/package.json +1 -1
package/components/Card.js
CHANGED
|
@@ -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
|
|
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} 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
|
|
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;
|
|
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
|
-
|
|
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.
|
|
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.
|
|
90
|
+
this.childPositions.clear();
|
|
91
|
+
if (this.autoLayout) this.layout();
|
|
73
92
|
}
|
|
74
93
|
|
|
75
94
|
/**
|
|
76
|
-
* Organise les enfants selon le layout
|
|
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.
|
|
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
|
-
//
|
|
89
|
-
|
|
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
|
-
|
|
110
|
+
childX = (this.width - child.width) / 2;
|
|
94
111
|
} else if (this.align === 'end') {
|
|
95
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
140
|
+
childY = (this.height - child.height) / 2;
|
|
125
141
|
} else if (this.align === 'end') {
|
|
126
|
-
|
|
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'
|
|
394
|
+
* @param {string} align - 'start', 'center', 'end'
|
|
350
395
|
*/
|
|
351
396
|
setAlign(align) {
|
|
352
|
-
if (['start', 'center', 'end'
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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;
|