canvasframework 0.5.25 → 0.5.27
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 +202 -25
- package/package.json +1 -1
package/components/Card.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import Component from '../core/Component.js';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* Container avec système de layout et effet d'élévation
|
|
4
5
|
* @class
|
|
5
6
|
* @extends Component
|
|
6
7
|
* @property {Component[]} children - Enfants
|
|
7
8
|
* @property {number} padding - Padding interne
|
|
8
|
-
* @property {number} gap - Espacement entre enfants
|
|
9
|
+
* @property {number} gap - Espacement constant entre enfants SEULEMENT
|
|
9
10
|
* @property {string} direction - Direction ('column' ou 'row')
|
|
10
|
-
* @property {string} align - Alignement ('start', 'center', 'end')
|
|
11
|
+
* @property {string} align - Alignement ('start', 'center', 'end', 'stretch')
|
|
11
12
|
* @property {string} bgColor - Couleur de fond
|
|
12
13
|
* @property {number} borderRadius - Rayon des coins
|
|
13
14
|
* @property {number} elevation - Niveau d'élévation (ombres)
|
|
@@ -18,7 +19,7 @@ class Card extends Component {
|
|
|
18
19
|
* @param {CanvasFramework} framework - Framework parent
|
|
19
20
|
* @param {Object} [options={}] - Options de configuration
|
|
20
21
|
* @param {number} [options.padding=0] - Padding interne
|
|
21
|
-
* @param {number} [options.gap=0] - Espacement entre enfants
|
|
22
|
+
* @param {number} [options.gap=0] - Espacement constant entre enfants SEULEMENT
|
|
22
23
|
* @param {string} [options.direction='column'] - Direction
|
|
23
24
|
* @param {string} [options.align='start'] - Alignement
|
|
24
25
|
* @param {string} [options.bgColor='transparent'] - Couleur de fond
|
|
@@ -29,12 +30,12 @@ class Card extends Component {
|
|
|
29
30
|
super(framework, options);
|
|
30
31
|
this.children = [];
|
|
31
32
|
this.padding = options.padding || 0;
|
|
32
|
-
this.gap = options.gap || 0;
|
|
33
|
+
this.gap = options.gap || 0; // Espacement UNIQUEMENT entre enfants
|
|
33
34
|
this.direction = options.direction || 'column';
|
|
34
35
|
this.align = options.align || 'start';
|
|
35
36
|
this.bgColor = options.bgColor || 'transparent';
|
|
36
37
|
this.borderRadius = options.borderRadius || 0;
|
|
37
|
-
this.elevation = options.elevation || 0;
|
|
38
|
+
this.elevation = options.elevation || 0;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -49,32 +50,94 @@ class Card extends Component {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|
|
52
|
-
*
|
|
53
|
+
* Supprime un enfant
|
|
54
|
+
* @param {Component} child - Composant enfant à supprimer
|
|
55
|
+
* @returns {boolean} True si l'enfant a été supprimé
|
|
56
|
+
*/
|
|
57
|
+
remove(child) {
|
|
58
|
+
const index = this.children.indexOf(child);
|
|
59
|
+
if (index > -1) {
|
|
60
|
+
this.children.splice(index, 1);
|
|
61
|
+
this.layout();
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Supprime tous les enfants
|
|
69
|
+
*/
|
|
70
|
+
clear() {
|
|
71
|
+
this.children = [];
|
|
72
|
+
this.layout();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Organise les enfants selon le layout avec espacement constant
|
|
53
77
|
* @private
|
|
54
78
|
*/
|
|
55
79
|
layout() {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
80
|
+
if (this.children.length === 0) return;
|
|
81
|
+
|
|
82
|
+
if (this.direction === 'column') {
|
|
83
|
+
let currentY = this.y + this.padding;
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
86
|
+
const child = this.children[i];
|
|
87
|
+
|
|
88
|
+
// Positionner l'enfant sans tenir compte de ses marges internes
|
|
62
89
|
child.y = currentY;
|
|
90
|
+
|
|
91
|
+
// Gérer l'alignement horizontal
|
|
63
92
|
if (this.align === 'center') {
|
|
64
93
|
child.x = this.x + (this.width - child.width) / 2;
|
|
65
94
|
} else if (this.align === 'end') {
|
|
66
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;
|
|
67
102
|
}
|
|
68
|
-
|
|
69
|
-
|
|
103
|
+
|
|
104
|
+
// Mettre à jour la position Y pour l'enfant suivant
|
|
105
|
+
// UNIQUEMENT avec le gap spécifié, rien d'autre
|
|
106
|
+
currentY += child.height;
|
|
107
|
+
|
|
108
|
+
// Ajouter le gap seulement si ce n'est pas le dernier enfant
|
|
109
|
+
if (i < this.children.length - 1) {
|
|
110
|
+
currentY += this.gap;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// Direction 'row'
|
|
115
|
+
let currentX = this.x + this.padding;
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
118
|
+
const child = this.children[i];
|
|
119
|
+
|
|
70
120
|
child.x = currentX;
|
|
71
|
-
|
|
121
|
+
|
|
122
|
+
// Gérer l'alignement vertical
|
|
72
123
|
if (this.align === 'center') {
|
|
73
124
|
child.y = this.y + (this.height - child.height) / 2;
|
|
74
125
|
} else if (this.align === 'end') {
|
|
75
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;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Mettre à jour la position X pour l'enfant suivant
|
|
135
|
+
currentX += child.width;
|
|
136
|
+
|
|
137
|
+
// Ajouter le gap seulement si ce n'est pas le dernier enfant
|
|
138
|
+
if (i < this.children.length - 1) {
|
|
139
|
+
currentX += this.gap;
|
|
76
140
|
}
|
|
77
|
-
currentX += child.width + this.gap;
|
|
78
141
|
}
|
|
79
142
|
}
|
|
80
143
|
}
|
|
@@ -87,12 +150,12 @@ class Card extends Component {
|
|
|
87
150
|
*/
|
|
88
151
|
getShadowConfig(elevation) {
|
|
89
152
|
const shadows = [
|
|
90
|
-
{ blur: 0, offsetY: 0, color: 'transparent', spread: 0 },
|
|
91
|
-
{ blur: 2, offsetY: 1, color: 'rgba(0,0,0,0.12)', spread: 0 },
|
|
92
|
-
{ blur: 3, offsetY: 1, color: 'rgba(0,0,0,0.14)', spread: 0 },
|
|
93
|
-
{ blur: 4, offsetY: 2, color: 'rgba(0,0,0,0.16)', spread: 0 },
|
|
94
|
-
{ blur: 6, offsetY: 3, color: 'rgba(0,0,0,0.18)', spread: 0 },
|
|
95
|
-
{ blur: 8, offsetY: 4, color: 'rgba(0,0,0,0.20)', spread: 0 },
|
|
153
|
+
{ blur: 0, offsetY: 0, color: 'transparent', spread: 0 },
|
|
154
|
+
{ blur: 2, offsetY: 1, color: 'rgba(0,0,0,0.12)', spread: 0 },
|
|
155
|
+
{ blur: 3, offsetY: 1, color: 'rgba(0,0,0,0.14)', spread: 0 },
|
|
156
|
+
{ blur: 4, offsetY: 2, color: 'rgba(0,0,0,0.16)', spread: 0 },
|
|
157
|
+
{ blur: 6, offsetY: 3, color: 'rgba(0,0,0,0.18)', spread: 0 },
|
|
158
|
+
{ blur: 8, offsetY: 4, color: 'rgba(0,0,0,0.20)', spread: 0 },
|
|
96
159
|
];
|
|
97
160
|
|
|
98
161
|
return shadows[Math.min(elevation, shadows.length - 1)];
|
|
@@ -108,16 +171,13 @@ class Card extends Component {
|
|
|
108
171
|
|
|
109
172
|
const shadow = this.getShadowConfig(this.elevation);
|
|
110
173
|
|
|
111
|
-
// Sauvegarder l'état du contexte
|
|
112
174
|
ctx.save();
|
|
113
175
|
|
|
114
|
-
// Configurer l'ombre
|
|
115
176
|
ctx.shadowColor = shadow.color;
|
|
116
177
|
ctx.shadowBlur = shadow.blur;
|
|
117
178
|
ctx.shadowOffsetX = 0;
|
|
118
179
|
ctx.shadowOffsetY = shadow.offsetY;
|
|
119
180
|
|
|
120
|
-
// Dessiner un rectangle pour l'ombre
|
|
121
181
|
if (this.borderRadius > 0) {
|
|
122
182
|
ctx.beginPath();
|
|
123
183
|
this.roundRect(ctx, this.x, this.y + shadow.offsetY, this.width, this.height, this.borderRadius);
|
|
@@ -174,6 +234,12 @@ class Card extends Component {
|
|
|
174
234
|
* @private
|
|
175
235
|
*/
|
|
176
236
|
roundRect(ctx, x, y, width, height, radius) {
|
|
237
|
+
if (radius === 0) {
|
|
238
|
+
ctx.rect(x, y, width, height);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
ctx.beginPath();
|
|
177
243
|
ctx.moveTo(x + radius, y);
|
|
178
244
|
ctx.lineTo(x + width - radius, y);
|
|
179
245
|
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
|
@@ -183,6 +249,7 @@ class Card extends Component {
|
|
|
183
249
|
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
|
184
250
|
ctx.lineTo(x, y + radius);
|
|
185
251
|
ctx.quadraticCurveTo(x, y, x + radius, y);
|
|
252
|
+
ctx.closePath();
|
|
186
253
|
}
|
|
187
254
|
|
|
188
255
|
/**
|
|
@@ -219,6 +286,116 @@ class Card extends Component {
|
|
|
219
286
|
lower() {
|
|
220
287
|
this.setElevation(this.elevation - 1);
|
|
221
288
|
}
|
|
289
|
+
|
|
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
|
+
/**
|
|
319
|
+
* Définit l'espacement entre enfants
|
|
320
|
+
* @param {number} gap - Nouvel espacement
|
|
321
|
+
*/
|
|
322
|
+
setGap(gap) {
|
|
323
|
+
this.gap = Math.max(0, gap);
|
|
324
|
+
this.layout();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Définit le padding
|
|
329
|
+
* @param {number} padding - Nouveau padding
|
|
330
|
+
*/
|
|
331
|
+
setPadding(padding) {
|
|
332
|
+
this.padding = Math.max(0, padding);
|
|
333
|
+
this.layout();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Définit la direction du layout
|
|
338
|
+
* @param {string} direction - 'column' ou 'row'
|
|
339
|
+
*/
|
|
340
|
+
setDirection(direction) {
|
|
341
|
+
if (direction === 'column' || direction === 'row') {
|
|
342
|
+
this.direction = direction;
|
|
343
|
+
this.layout();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Définit l'alignement
|
|
349
|
+
* @param {string} align - 'start', 'center', 'end' ou 'stretch'
|
|
350
|
+
*/
|
|
351
|
+
setAlign(align) {
|
|
352
|
+
if (['start', 'center', 'end', 'stretch'].includes(align)) {
|
|
353
|
+
this.align = align;
|
|
354
|
+
this.layout();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Calcule la hauteur totale nécessaire pour contenir tous les enfants
|
|
360
|
+
* @returns {number} Hauteur totale nécessaire
|
|
361
|
+
*/
|
|
362
|
+
getTotalHeight() {
|
|
363
|
+
if (this.children.length === 0) return 0;
|
|
364
|
+
|
|
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);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Calcule la largeur totale nécessaire pour contenir tous les enfants
|
|
372
|
+
* @returns {number} Largeur totale nécessaire
|
|
373
|
+
*/
|
|
374
|
+
getTotalWidth() {
|
|
375
|
+
if (this.children.length === 0) return 0;
|
|
376
|
+
|
|
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);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Ajuste automatiquement la hauteur de la carte pour contenir tous les enfants
|
|
384
|
+
*/
|
|
385
|
+
fitHeight() {
|
|
386
|
+
if (this.direction === 'column') {
|
|
387
|
+
this.height = this.getTotalHeight();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Ajuste automatiquement la largeur de la carte pour contenir tous les enfants
|
|
393
|
+
*/
|
|
394
|
+
fitWidth() {
|
|
395
|
+
if (this.direction === 'row') {
|
|
396
|
+
this.width = this.getTotalWidth();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
222
399
|
}
|
|
223
400
|
|
|
224
401
|
export default Card;
|