canvasframework 0.5.38 → 0.5.39

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 +282 -1
  2. package/package.json +1 -1
@@ -42,6 +42,217 @@ class Card extends Component {
42
42
 
43
43
  // Stocker les positions relatives des enfants
44
44
  this.childPositions = new Map();
45
+
46
+ // NOUVEAU: Gestion des événements
47
+ this._canvas = null;
48
+ this._isTouchDevice = false;
49
+ this._clickListeners = new Map();
50
+ this._touchListeners = new Map();
51
+ this._enabled = options.enabled !== undefined ? options.enabled : true;
52
+ this._interactive = options.interactive !== undefined ? options.interactive : true;
53
+
54
+ // NOUVEAU: Pour le hot reload, nettoyer les anciens événements
55
+ if (typeof window !== 'undefined') {
56
+ this._setupEventCleanup();
57
+ }
58
+ }
59
+
60
+ // NOUVEAU: Initialisation des événements
61
+ _initEvents() {
62
+ if (!this.framework || !this.framework.canvas) return;
63
+
64
+ this._canvas = this.framework.canvas;
65
+
66
+ // Détecter si on est sur mobile/touch
67
+ this._isTouchDevice = 'ontouchstart' in window ||
68
+ navigator.maxTouchPoints > 0 ||
69
+ navigator.msMaxTouchPoints > 0;
70
+
71
+ // Écouter les événements sur le canvas
72
+ this._canvas.addEventListener('click', this._handleCanvasClick.bind(this));
73
+ this._canvas.addEventListener('touchstart', this._handleCanvasTouch.bind(this), { passive: false });
74
+ this._canvas.addEventListener('touchend', this._handleCanvasTouchEnd.bind(this), { passive: false });
75
+ }
76
+
77
+ // NOUVEAU: Nettoyage pour hot reload Vite
78
+ _setupEventCleanup() {
79
+ // Avant que la page ne soit déchargée (pour hot reload)
80
+ window.addEventListener('beforeunload', () => {
81
+ this._cleanupEvents();
82
+ });
83
+ }
84
+
85
+ // NOUVEAU: Nettoyer les événements
86
+ _cleanupEvents() {
87
+ if (this._canvas) {
88
+ this._canvas.removeEventListener('click', this._handleCanvasClick);
89
+ this._canvas.removeEventListener('touchstart', this._handleCanvasTouch);
90
+ this._canvas.removeEventListener('touchend', this._handleCanvasTouchEnd);
91
+ }
92
+ this._clickListeners.clear();
93
+ this._touchListeners.clear();
94
+ }
95
+
96
+ // NOUVEAU: Convertir les coordonnées du DOM vers canvas
97
+ _getCanvasCoordinates(clientX, clientY) {
98
+ if (!this._canvas) return { x: 0, y: 0 };
99
+
100
+ const rect = this._canvas.getBoundingClientRect();
101
+ const scaleX = this._canvas.width / rect.width;
102
+ const scaleY = this._canvas.height / rect.height;
103
+
104
+ return {
105
+ x: (clientX - rect.left) * scaleX,
106
+ y: (clientY - rect.top) * scaleY
107
+ };
108
+ }
109
+
110
+ // NOUVEAU: Gérer les clics sur le canvas
111
+ _handleCanvasClick(event) {
112
+ if (!this._enabled || !this.visible || !this._interactive) return;
113
+
114
+ const coords = this._getCanvasCoordinates(event.clientX, event.clientY);
115
+
116
+ // Vérifier si le clic est sur cette carte
117
+ if (this.isPointInside(coords.x, coords.y)) {
118
+ // Empêcher le comportement par défaut
119
+ event.preventDefault();
120
+ event.stopPropagation();
121
+
122
+ // Déclencher l'événement onClick de la carte
123
+ if (this.onClick) {
124
+ const localCoords = {
125
+ x: coords.x - this.x,
126
+ y: coords.y - this.y
127
+ };
128
+ this.onClick({
129
+ type: 'click',
130
+ x: localCoords.x,
131
+ y: localCoords.y,
132
+ clientX: event.clientX,
133
+ clientY: event.clientY,
134
+ originalEvent: event,
135
+ target: this
136
+ });
137
+ }
138
+
139
+ // Vérifier si un enfant est cliqué
140
+ this._propagateClickToChildren(coords.x, coords.y, event);
141
+ }
142
+ }
143
+
144
+ // NOUVEAU: Gérer les touches tactiles
145
+ _handleCanvasTouch(event) {
146
+ if (!this._enabled || !this.visible || !this._interactive) return;
147
+
148
+ if (event.touches.length > 0) {
149
+ event.preventDefault();
150
+ event.stopPropagation();
151
+
152
+ const touch = event.touches[0];
153
+ const coords = this._getCanvasCoordinates(touch.clientX, touch.clientY);
154
+
155
+ // Stocker la position de départ du touch
156
+ this._lastTouchStart = { x: coords.x, y: coords.y };
157
+
158
+ // Vérifier si le touch est sur cette carte
159
+ if (this.isPointInside(coords.x, coords.y)) {
160
+ // Déclencher l'événement onTouchStart de la carte
161
+ if (this.onTouchStart) {
162
+ const localCoords = {
163
+ x: coords.x - this.x,
164
+ y: coords.y - this.y
165
+ };
166
+ this.onTouchStart({
167
+ type: 'touchstart',
168
+ x: localCoords.x,
169
+ y: localCoords.y,
170
+ clientX: touch.clientX,
171
+ clientY: touch.clientY,
172
+ originalEvent: event,
173
+ target: this
174
+ });
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ // NOUVEAU: Gérer la fin des touches tactiles
181
+ _handleCanvasTouchEnd(event) {
182
+ if (!this._enabled || !this.visible || !this._interactive) return;
183
+
184
+ event.preventDefault();
185
+ event.stopPropagation();
186
+
187
+ if (event.changedTouches.length > 0) {
188
+ const touch = event.changedTouches[0];
189
+ const coords = this._getCanvasCoordinates(touch.clientX, touch.clientY);
190
+
191
+ // Vérifier si le touch end est sur cette carte
192
+ if (this.isPointInside(coords.x, coords.y)) {
193
+ // Déclencher l'événement onTouchEnd de la carte
194
+ if (this.onTouchEnd) {
195
+ const localCoords = {
196
+ x: coords.x - this.x,
197
+ y: coords.y - this.y
198
+ };
199
+ this.onTouchEnd({
200
+ type: 'touchend',
201
+ x: localCoords.x,
202
+ y: localCoords.y,
203
+ clientX: touch.clientX,
204
+ clientY: touch.clientY,
205
+ originalEvent: event,
206
+ target: this
207
+ });
208
+ }
209
+
210
+ // Simuler un clic si le touch start était sur la même position
211
+ if (this._lastTouchStart &&
212
+ Math.abs(coords.x - this._lastTouchStart.x) < 10 &&
213
+ Math.abs(coords.y - this._lastTouchStart.y) < 10) {
214
+ this._propagateClickToChildren(coords.x, coords.y, event);
215
+ }
216
+
217
+ this._lastTouchStart = null;
218
+ }
219
+ }
220
+ }
221
+
222
+ // NOUVEAU: Propager le clic aux enfants
223
+ _propagateClickToChildren(canvasX, canvasY, originalEvent) {
224
+ // Parcourir les enfants du dernier au premier (z-order)
225
+ for (let i = this.children.length - 1; i >= 0; i--) {
226
+ const child = this.children[i];
227
+
228
+ // Vérifier si l'enfant est visible et interactif
229
+ const childEnabled = child._enabled !== undefined ? child._enabled : true;
230
+ const childInteractive = child._interactive !== undefined ? child._interactive : true;
231
+
232
+ if (child.visible && childEnabled && childInteractive &&
233
+ child.isPointInside(canvasX, canvasY)) {
234
+
235
+ // Déclencher l'événement onClick de l'enfant
236
+ if (child.onClick) {
237
+ const localCoords = {
238
+ x: canvasX - child.x,
239
+ y: canvasY - child.y
240
+ };
241
+ child.onClick({
242
+ type: 'click',
243
+ x: localCoords.x,
244
+ y: localCoords.y,
245
+ clientX: originalEvent.clientX,
246
+ clientY: originalEvent.clientY,
247
+ originalEvent: originalEvent,
248
+ target: child
249
+ });
250
+ }
251
+
252
+ // Stopper la propagation après avoir trouvé un enfant cliqué
253
+ break;
254
+ }
255
+ }
45
256
  }
46
257
 
47
258
  /**
@@ -53,7 +264,6 @@ class Card extends Component {
53
264
  this.children.push(child);
54
265
 
55
266
  // CONVERTIR les positions relatives en positions absolues
56
- // Les x, y passés sont relatifs à la Card
57
267
  child.x = this.x + child.x;
58
268
  child.y = this.y + child.y;
59
269
 
@@ -63,6 +273,11 @@ class Card extends Component {
63
273
  y: child.y - this.y
64
274
  });
65
275
 
276
+ // NOUVEAU: Initialiser les événements si c'est la première fois
277
+ if (this.children.length === 1 && this._canvas === null) {
278
+ this._initEvents();
279
+ }
280
+
66
281
  // Si autoLayout est activé, organiser automatiquement
67
282
  if (this.autoLayout) {
68
283
  this.layout();
@@ -335,12 +550,63 @@ class Card extends Component {
335
550
  * @returns {boolean} True si le point est dans la vue
336
551
  */
337
552
  isPointInside(x, y) {
553
+ // Pour les rectangles arrondis, vérification plus précise
554
+ if (this.borderRadius > 0) {
555
+ return this._isPointInRoundedRect(x, y);
556
+ }
557
+
558
+ // Pour les rectangles normaux
338
559
  return x >= this.x &&
339
560
  x <= this.x + this.width &&
340
561
  y >= this.y &&
341
562
  y <= this.y + this.height;
342
563
  }
343
564
 
565
+ // NOUVEAU: Vérifier si un point est dans un rectangle arrondi
566
+ _isPointInRoundedRect(x, y) {
567
+ const rectX = this.x;
568
+ const rectY = this.y;
569
+ const width = this.width;
570
+ const height = this.height;
571
+ const radius = this.borderRadius;
572
+
573
+ // Vérifier la zone centrale (sans les coins arrondis)
574
+ if (x >= rectX + radius && x <= rectX + width - radius &&
575
+ y >= rectY && y <= rectY + height) {
576
+ return true;
577
+ }
578
+ if (x >= rectX && x <= rectX + width &&
579
+ y >= rectY + radius && y <= rectY + height - radius) {
580
+ return true;
581
+ }
582
+
583
+ // Vérifier les quatre coins arrondis
584
+ const checkCorner = (cornerX, cornerY) => {
585
+ const dx = x - cornerX;
586
+ const dy = y - cornerY;
587
+ return (dx * dx + dy * dy) <= (radius * radius);
588
+ };
589
+
590
+ // Coin supérieur gauche
591
+ if (x < rectX + radius && y < rectY + radius) {
592
+ return checkCorner(rectX + radius, rectY + radius);
593
+ }
594
+ // Coin supérieur droit
595
+ if (x > rectX + width - radius && y < rectY + radius) {
596
+ return checkCorner(rectX + width - radius, rectY + radius);
597
+ }
598
+ // Coin inférieur gauche
599
+ if (x < rectX + radius && y > rectY + height - radius) {
600
+ return checkCorner(rectX + radius, rectY + height - radius);
601
+ }
602
+ // Coin inférieur droit
603
+ if (x > rectX + width - radius && y > rectY + height - radius) {
604
+ return checkCorner(rectX + width - radius, rectY + height - radius);
605
+ }
606
+
607
+ return false;
608
+ }
609
+
344
610
  /**
345
611
  * Définit le niveau d'élévation
346
612
  * @param {number} elevation - Nouveau niveau d'élévation (0-5)
@@ -477,6 +743,21 @@ class Card extends Component {
477
743
  getChildPosition(child) {
478
744
  return this.childPositions.get(child) || null;
479
745
  }
746
+
747
+ // NOUVEAU: Méthodes pour activer/désactiver l'interactivité
748
+ setEnabled(enabled) {
749
+ this._enabled = enabled;
750
+ }
751
+
752
+ setInteractive(interactive) {
753
+ this._interactive = interactive;
754
+ }
755
+
756
+ // NOUVEAU: Méthode de nettoyage
757
+ destroy() {
758
+ this._cleanupEvents();
759
+ super.destroy();
760
+ }
480
761
  }
481
762
 
482
763
  export default Card;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.5.38",
3
+ "version": "0.5.39",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/beyons/CanvasFramework.git"