canvasframework 0.5.55 → 0.5.57
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/QRCodeGenerator.js +307 -0
- package/core/CanvasFramework.js +1 -0
- package/core/UIBuilder.js +2 -0
- package/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import Component from '../core/Component.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* QRCodeGenerator SANS librairie externe
|
|
5
|
+
* Version simplifiée qui fonctionne pour texte court et URLs
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* new QRCodeGenerator(framework, {
|
|
9
|
+
* x: 50,
|
|
10
|
+
* y: 100,
|
|
11
|
+
* width: 250,
|
|
12
|
+
* height: 250,
|
|
13
|
+
* data: 'https://example.com'
|
|
14
|
+
* });
|
|
15
|
+
*/
|
|
16
|
+
class QRCodeGenerator extends Component {
|
|
17
|
+
constructor(framework, options = {}) {
|
|
18
|
+
super(framework, options);
|
|
19
|
+
|
|
20
|
+
// Données du QR code
|
|
21
|
+
this.data = options.data || options.text || 'Hello';
|
|
22
|
+
|
|
23
|
+
// Dimensions
|
|
24
|
+
this.width = options.width || 250;
|
|
25
|
+
this.height = options.height || 250;
|
|
26
|
+
this.qrSize = Math.min(this.width, this.height);
|
|
27
|
+
|
|
28
|
+
// Options visuelles
|
|
29
|
+
this.backgroundColor = options.backgroundColor || '#ffffff';
|
|
30
|
+
this.foregroundColor = options.foregroundColor || '#000000';
|
|
31
|
+
this.padding = options.padding || 20;
|
|
32
|
+
|
|
33
|
+
// État
|
|
34
|
+
this.qrMatrix = null;
|
|
35
|
+
this.moduleSize = 0;
|
|
36
|
+
|
|
37
|
+
// Générer immédiatement
|
|
38
|
+
this.generateQRCode();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async _mount() {
|
|
42
|
+
super._mount?.();
|
|
43
|
+
if (!this.qrMatrix) {
|
|
44
|
+
this.generateQRCode();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
destroy() {
|
|
49
|
+
this.qrMatrix = null;
|
|
50
|
+
super.destroy?.();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onUnmount() {
|
|
54
|
+
console.log('[QRCodeGenerator] onUnmount called');
|
|
55
|
+
this.qrMatrix = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Génère un QR code simple (Version 1 : 21x21)
|
|
60
|
+
*/
|
|
61
|
+
generateQRCode() {
|
|
62
|
+
try {
|
|
63
|
+
// Taille fixe pour Version 1 (supporte ~25 caractères)
|
|
64
|
+
const size = 21;
|
|
65
|
+
|
|
66
|
+
// Créer la matrice
|
|
67
|
+
this.qrMatrix = this.createMatrix(size);
|
|
68
|
+
|
|
69
|
+
// Ajouter les patterns de base
|
|
70
|
+
this.addFinderPatterns(this.qrMatrix);
|
|
71
|
+
this.addTimingPatterns(this.qrMatrix);
|
|
72
|
+
this.addAlignmentPattern(this.qrMatrix);
|
|
73
|
+
|
|
74
|
+
// Ajouter les données (simplifié)
|
|
75
|
+
this.addDataSimple(this.qrMatrix);
|
|
76
|
+
|
|
77
|
+
// Calculer la taille d'un module
|
|
78
|
+
const availableSize = this.qrSize - (this.padding * 2);
|
|
79
|
+
this.moduleSize = Math.floor(availableSize / size);
|
|
80
|
+
|
|
81
|
+
console.log('[QRCodeGenerator] QR Code generated:', size + 'x' + size);
|
|
82
|
+
this.markDirty();
|
|
83
|
+
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error('[QRCodeGenerator] Error:', err);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Crée une matrice vide
|
|
91
|
+
*/
|
|
92
|
+
createMatrix(size) {
|
|
93
|
+
const matrix = [];
|
|
94
|
+
for (let i = 0; i < size; i++) {
|
|
95
|
+
matrix[i] = new Array(size).fill(-1); // -1 = non défini
|
|
96
|
+
}
|
|
97
|
+
return matrix;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Ajoute les patterns de position (3 carrés dans les coins)
|
|
102
|
+
*/
|
|
103
|
+
addFinderPatterns(matrix) {
|
|
104
|
+
const size = matrix.length;
|
|
105
|
+
|
|
106
|
+
// Pattern 7x7
|
|
107
|
+
const addFinder = (startX, startY) => {
|
|
108
|
+
for (let dy = 0; dy < 7; dy++) {
|
|
109
|
+
for (let dx = 0; dx < 7; dx++) {
|
|
110
|
+
const x = startX + dx;
|
|
111
|
+
const y = startY + dy;
|
|
112
|
+
|
|
113
|
+
// Carré extérieur (7x7)
|
|
114
|
+
if (dx === 0 || dx === 6 || dy === 0 || dy === 6) {
|
|
115
|
+
matrix[y][x] = 1;
|
|
116
|
+
}
|
|
117
|
+
// Carré intérieur (3x3) centré
|
|
118
|
+
else if (dx >= 2 && dx <= 4 && dy >= 2 && dy <= 4) {
|
|
119
|
+
matrix[y][x] = 1;
|
|
120
|
+
}
|
|
121
|
+
// Blanc entre les deux
|
|
122
|
+
else {
|
|
123
|
+
matrix[y][x] = 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Séparateurs blancs (1 pixel autour)
|
|
129
|
+
for (let i = 0; i < 8; i++) {
|
|
130
|
+
if (startX === 0 && startY === 0) {
|
|
131
|
+
// Haut gauche
|
|
132
|
+
if (i < 7) matrix[7][i] = 0;
|
|
133
|
+
if (i < 7) matrix[i][7] = 0;
|
|
134
|
+
} else if (startX === size - 7 && startY === 0) {
|
|
135
|
+
// Haut droit
|
|
136
|
+
if (i < 7) matrix[7][size - 8 + i] = 0;
|
|
137
|
+
if (i < 7) matrix[i][size - 8] = 0;
|
|
138
|
+
} else if (startX === 0 && startY === size - 7) {
|
|
139
|
+
// Bas gauche
|
|
140
|
+
if (i < 7) matrix[size - 8][i] = 0;
|
|
141
|
+
if (i < 7) matrix[size - 8 + i][7] = 0;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Haut gauche
|
|
147
|
+
addFinder(0, 0);
|
|
148
|
+
|
|
149
|
+
// Haut droit
|
|
150
|
+
addFinder(size - 7, 0);
|
|
151
|
+
|
|
152
|
+
// Bas gauche
|
|
153
|
+
addFinder(0, size - 7);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Ajoute les lignes de timing
|
|
158
|
+
*/
|
|
159
|
+
addTimingPatterns(matrix) {
|
|
160
|
+
const size = matrix.length;
|
|
161
|
+
|
|
162
|
+
// Ligne horizontale (ligne 6)
|
|
163
|
+
for (let i = 8; i < size - 8; i++) {
|
|
164
|
+
matrix[6][i] = (i % 2 === 0) ? 1 : 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Ligne verticale (colonne 6)
|
|
168
|
+
for (let i = 8; i < size - 8; i++) {
|
|
169
|
+
matrix[i][6] = (i % 2 === 0) ? 1 : 0;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Ajoute le pattern d'alignement (pour Version 1, pas nécessaire, mais on le met quand même)
|
|
175
|
+
*/
|
|
176
|
+
addAlignmentPattern(matrix) {
|
|
177
|
+
// Pour Version 1, pas d'alignment pattern
|
|
178
|
+
// On remplit juste avec le module noir obligatoire
|
|
179
|
+
const size = matrix.length;
|
|
180
|
+
matrix[size - 8][8] = 1; // Module noir fixe
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Ajoute les données de manière simplifiée (pattern basé sur les données)
|
|
185
|
+
*/
|
|
186
|
+
addDataSimple(matrix) {
|
|
187
|
+
const size = matrix.length;
|
|
188
|
+
|
|
189
|
+
// Convertir les données en une séquence de bits basique
|
|
190
|
+
let bits = '';
|
|
191
|
+
for (let i = 0; i < this.data.length; i++) {
|
|
192
|
+
const charCode = this.data.charCodeAt(i);
|
|
193
|
+
// Convertir en binaire sur 8 bits
|
|
194
|
+
bits += charCode.toString(2).padStart(8, '0');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Ajouter un padding si nécessaire
|
|
198
|
+
while (bits.length < 100) {
|
|
199
|
+
bits += '0';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let bitIndex = 0;
|
|
203
|
+
|
|
204
|
+
// Remplir la matrice en zigzag (de droite à gauche, de bas en haut)
|
|
205
|
+
for (let col = size - 1; col > 0; col -= 2) {
|
|
206
|
+
// Sauter la colonne de timing
|
|
207
|
+
if (col === 6) col--;
|
|
208
|
+
|
|
209
|
+
for (let row = 0; row < size; row++) {
|
|
210
|
+
// Alterner direction : bas->haut puis haut->bas
|
|
211
|
+
const y = ((col + 1) % 4 < 2) ? (size - 1 - row) : row;
|
|
212
|
+
|
|
213
|
+
// Remplir 2 colonnes à la fois
|
|
214
|
+
for (let c = 0; c < 2; c++) {
|
|
215
|
+
const x = col - c;
|
|
216
|
+
|
|
217
|
+
// Ne pas écraser les patterns existants
|
|
218
|
+
if (matrix[y][x] !== -1) continue;
|
|
219
|
+
|
|
220
|
+
// Placer un bit
|
|
221
|
+
if (bitIndex < bits.length) {
|
|
222
|
+
matrix[y][x] = bits[bitIndex] === '1' ? 1 : 0;
|
|
223
|
+
bitIndex++;
|
|
224
|
+
} else {
|
|
225
|
+
matrix[y][x] = 0;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Remplir les cases restantes avec 0
|
|
232
|
+
for (let y = 0; y < size; y++) {
|
|
233
|
+
for (let x = 0; x < size; x++) {
|
|
234
|
+
if (matrix[y][x] === -1) {
|
|
235
|
+
matrix[y][x] = 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Change les données et régénère
|
|
243
|
+
*/
|
|
244
|
+
async setData(newData) {
|
|
245
|
+
if (this.data === newData) return;
|
|
246
|
+
this.data = newData;
|
|
247
|
+
this.generateQRCode();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Change la taille
|
|
252
|
+
*/
|
|
253
|
+
async setSize(newSize) {
|
|
254
|
+
this.width = newSize;
|
|
255
|
+
this.height = newSize;
|
|
256
|
+
this.qrSize = newSize;
|
|
257
|
+
this.generateQRCode();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
draw(ctx) {
|
|
261
|
+
ctx.save();
|
|
262
|
+
|
|
263
|
+
// Fond
|
|
264
|
+
ctx.fillStyle = this.backgroundColor;
|
|
265
|
+
ctx.fillRect(this.x, this.y, this.width, this.height);
|
|
266
|
+
|
|
267
|
+
if (!this.qrMatrix || this.moduleSize === 0) {
|
|
268
|
+
// Message de chargement
|
|
269
|
+
ctx.fillStyle = '#666';
|
|
270
|
+
ctx.font = '14px Arial';
|
|
271
|
+
ctx.textAlign = 'center';
|
|
272
|
+
ctx.textBaseline = 'middle';
|
|
273
|
+
ctx.fillText(
|
|
274
|
+
'Génération...',
|
|
275
|
+
this.x + this.width / 2,
|
|
276
|
+
this.y + this.height / 2
|
|
277
|
+
);
|
|
278
|
+
ctx.restore();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Centrer le QR code
|
|
283
|
+
const qrPixelSize = this.qrMatrix.length * this.moduleSize;
|
|
284
|
+
const offsetX = (this.width - qrPixelSize) / 2;
|
|
285
|
+
const offsetY = (this.height - qrPixelSize) / 2;
|
|
286
|
+
|
|
287
|
+
// Dessiner les modules
|
|
288
|
+
ctx.fillStyle = this.foregroundColor;
|
|
289
|
+
|
|
290
|
+
for (let y = 0; y < this.qrMatrix.length; y++) {
|
|
291
|
+
for (let x = 0; x < this.qrMatrix[y].length; x++) {
|
|
292
|
+
if (this.qrMatrix[y][x] === 1) {
|
|
293
|
+
ctx.fillRect(
|
|
294
|
+
this.x + offsetX + x * this.moduleSize,
|
|
295
|
+
this.y + offsetY + y * this.moduleSize,
|
|
296
|
+
this.moduleSize,
|
|
297
|
+
this.moduleSize
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
ctx.restore();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export default QRCodeGenerator;
|
package/core/CanvasFramework.js
CHANGED
|
@@ -59,6 +59,7 @@ import Camera from '../components/Camera.js';
|
|
|
59
59
|
import FloatedCamera from '../components/FloatedCamera.js';
|
|
60
60
|
import TimePicker from '../components/TimePicker.js';
|
|
61
61
|
import QRCodeReader from '../components/QRCodeReader.js';
|
|
62
|
+
import QRCodeGenerator from '../components/QRCodeGenerator.js';
|
|
62
63
|
|
|
63
64
|
// Utils
|
|
64
65
|
import SafeArea from '../utils/SafeArea.js';
|
package/core/UIBuilder.js
CHANGED
|
@@ -59,6 +59,7 @@ import Camera from '../components/Camera.js';
|
|
|
59
59
|
import FloatedCamera from '../components/FloatedCamera.js';
|
|
60
60
|
import TimePicker from '../components/TimePicker.js';
|
|
61
61
|
import QRCodeReader from '../components/QRCodeReader.js';
|
|
62
|
+
import QRCodeGenerator from '../components/QRCodeGenerator.js';
|
|
62
63
|
|
|
63
64
|
// Features
|
|
64
65
|
import PullToRefresh from '../features/PullToRefresh.js';
|
|
@@ -145,6 +146,7 @@ const Components = {
|
|
|
145
146
|
Positioned,
|
|
146
147
|
Banner,
|
|
147
148
|
Chart,
|
|
149
|
+
QRCodeGenerator,
|
|
148
150
|
Stack
|
|
149
151
|
};
|
|
150
152
|
|
package/index.js
CHANGED
|
@@ -66,6 +66,7 @@ export { default as Camera } from './components/Camera.js';
|
|
|
66
66
|
export { default as FloatedCamera } from './components/FloatedCamera.js';
|
|
67
67
|
export { default as TimePicker } from './components/TimePicker.js';
|
|
68
68
|
export { default as QRCodeReader } from './components/QRCodeReader.js';
|
|
69
|
+
export { default as QRCodeGenerator } from './components/QRCodeGenerator.js';
|
|
69
70
|
|
|
70
71
|
// Utils
|
|
71
72
|
export { default as SafeArea } from './utils/SafeArea.js';
|