canvasframework 0.3.29 → 0.4.1
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.
|
@@ -170,7 +170,7 @@ class AndroidDatePickerDialog extends Component {
|
|
|
170
170
|
ctx.shadowColor = 'transparent';
|
|
171
171
|
|
|
172
172
|
// Header coloré
|
|
173
|
-
ctx.fillStyle =
|
|
173
|
+
ctx.fillStyle = this.headerBgColor;
|
|
174
174
|
ctx.beginPath();
|
|
175
175
|
this.roundRect(ctx, dialogX, dialogY, this.dialogWidth, this.headerHeight, 4);
|
|
176
176
|
ctx.rect(dialogX, dialogY + this.headerHeight - 4, this.dialogWidth, 4);
|
|
@@ -191,7 +191,7 @@ class AndroidDatePickerDialog extends Component {
|
|
|
191
191
|
const selectedMonth = monthNames[this.selectedDate.getMonth()];
|
|
192
192
|
const selectedDayNum = this.selectedDate.getDate();
|
|
193
193
|
|
|
194
|
-
ctx.fillStyle = '#
|
|
194
|
+
ctx.fillStyle = '#ffffff';
|
|
195
195
|
ctx.font = 'bold 32px Roboto, sans-serif';
|
|
196
196
|
ctx.textBaseline = 'middle';
|
|
197
197
|
ctx.fillText(`${selectedDay}, ${selectedMonth} ${selectedDayNum}`,
|
package/core/CanvasFramework.js
CHANGED
|
@@ -196,6 +196,11 @@ class CanvasFramework {
|
|
|
196
196
|
|
|
197
197
|
this.components = [];
|
|
198
198
|
this.theme = lightTheme; // thème par défaut
|
|
199
|
+
// ✅ AJOUTER ICI :
|
|
200
|
+
this._cachedMaxScroll = 0;
|
|
201
|
+
this._maxScrollDirty = true;
|
|
202
|
+
this.resizeTimeout = null;
|
|
203
|
+
|
|
199
204
|
//this.applyThemeFromSystem();
|
|
200
205
|
this.state = {};
|
|
201
206
|
// NOUVELLE OPTION: choisir entre Canvas 2D et WebGL
|
|
@@ -1231,13 +1236,18 @@ class CanvasFramework {
|
|
|
1231
1236
|
}
|
|
1232
1237
|
|
|
1233
1238
|
getMaxScroll() {
|
|
1239
|
+
if (!this._maxScrollDirty) return this._cachedMaxScroll;
|
|
1240
|
+
|
|
1234
1241
|
let maxY = 0;
|
|
1235
1242
|
for (const comp of this.components) {
|
|
1236
1243
|
if (this.isFixedComponent(comp) || !comp.visible) continue;
|
|
1237
1244
|
const bottom = comp.y + comp.height;
|
|
1238
1245
|
if (bottom > maxY) maxY = bottom;
|
|
1239
1246
|
}
|
|
1240
|
-
|
|
1247
|
+
|
|
1248
|
+
this._cachedMaxScroll = Math.max(0, maxY - this.height + 50);
|
|
1249
|
+
this._maxScrollDirty = false;
|
|
1250
|
+
return this._cachedMaxScroll;
|
|
1241
1251
|
}
|
|
1242
1252
|
|
|
1243
1253
|
/*getMaxScroll() {
|
|
@@ -1251,32 +1261,38 @@ class CanvasFramework {
|
|
|
1251
1261
|
}*/
|
|
1252
1262
|
|
|
1253
1263
|
handleResize() {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
this.
|
|
1258
|
-
|
|
1264
|
+
if (this.resizeTimeout) clearTimeout(this.resizeTimeout); // ✅ AJOUTER
|
|
1265
|
+
|
|
1266
|
+
this.resizeTimeout = setTimeout(() => { // ✅ AJOUTER
|
|
1267
|
+
if (!this.useWebGL) {
|
|
1268
|
+
this.width = window.innerWidth;
|
|
1269
|
+
this.height = window.innerHeight;
|
|
1270
|
+
this.setupCanvas();
|
|
1259
1271
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1272
|
+
for (const comp of this.components) {
|
|
1273
|
+
if (comp._resize) {
|
|
1274
|
+
comp._resize(this.width, this.height);
|
|
1275
|
+
}
|
|
1263
1276
|
}
|
|
1277
|
+
this._maxScrollDirty = true; // ✅ AJOUTER
|
|
1264
1278
|
}
|
|
1265
|
-
}
|
|
1279
|
+
}, 150); // ✅ AJOUTER (throttle 150ms)
|
|
1266
1280
|
}
|
|
1267
1281
|
|
|
1268
1282
|
add(component) {
|
|
1269
1283
|
this.components.push(component);
|
|
1270
|
-
|
|
1284
|
+
component._mount();
|
|
1285
|
+
this._maxScrollDirty = true; // ✅ AJOUTER CETTE LIGNE
|
|
1271
1286
|
return component;
|
|
1272
1287
|
}
|
|
1273
1288
|
|
|
1274
1289
|
remove(component) {
|
|
1275
1290
|
const index = this.components.indexOf(component);
|
|
1276
1291
|
if (index > -1) {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1292
|
+
component._unmount();
|
|
1293
|
+
this.components.splice(index, 1);
|
|
1294
|
+
this._maxScrollDirty = true; // ✅ AJOUTER CETTE LIGNE
|
|
1295
|
+
}
|
|
1280
1296
|
}
|
|
1281
1297
|
|
|
1282
1298
|
markComponentDirty(component) {
|
|
@@ -1497,14 +1513,20 @@ class CanvasFramework {
|
|
|
1497
1513
|
}
|
|
1498
1514
|
|
|
1499
1515
|
// Scrollable
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1516
|
+
this.ctx.save();
|
|
1517
|
+
this.ctx.translate(0, this.scrollOffset);
|
|
1518
|
+
for (let comp of scrollableComponents) {
|
|
1519
|
+
if (comp.visible) {
|
|
1520
|
+
// ✅ Viewport culling : ne dessiner que ce qui est visible
|
|
1521
|
+
const screenY = comp.y + this.scrollOffset;
|
|
1522
|
+
const isInViewport = screenY + comp.height >= -100 && screenY <= this.height + 100;
|
|
1523
|
+
|
|
1524
|
+
if (isInViewport) {
|
|
1525
|
+
comp.draw(this.ctx);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
this.ctx.restore();
|
|
1508
1530
|
|
|
1509
1531
|
// Fixed
|
|
1510
1532
|
for (let comp of fixedComponents) {
|
|
@@ -83,6 +83,12 @@ class WebGLCanvasAdapter {
|
|
|
83
83
|
|
|
84
84
|
// Mode batch (true par défaut pour performance)
|
|
85
85
|
this.batchEnabled = true;
|
|
86
|
+
|
|
87
|
+
// ✅ AJOUTER CES LIGNES
|
|
88
|
+
this.colorCache = new Map();
|
|
89
|
+
this.colorCacheMaxSize = 100;
|
|
90
|
+
this.measureTextCache = new Map();
|
|
91
|
+
this.uniformLocations = null; // Sera initialisé dans initWebGL
|
|
86
92
|
|
|
87
93
|
this.initWebGL();
|
|
88
94
|
}
|
|
@@ -302,12 +308,19 @@ class WebGLCanvasAdapter {
|
|
|
302
308
|
}
|
|
303
309
|
|
|
304
310
|
measureText(text) {
|
|
311
|
+
const cacheKey = `${text}_${this.state.font}`;
|
|
312
|
+
|
|
313
|
+
// ✅ Cache lookup
|
|
314
|
+
if (this.measureTextCache.has(cacheKey)) {
|
|
315
|
+
return this.measureTextCache.get(cacheKey);
|
|
316
|
+
}
|
|
317
|
+
|
|
305
318
|
this.textCtx.save();
|
|
306
319
|
this.textCtx.font = this.state.font;
|
|
307
320
|
const metrics = this.textCtx.measureText(text);
|
|
308
321
|
this.textCtx.restore();
|
|
309
|
-
|
|
310
|
-
|
|
322
|
+
|
|
323
|
+
const result = {
|
|
311
324
|
width: metrics.width,
|
|
312
325
|
actualBoundingBoxAscent: metrics.actualBoundingBoxAscent || 0,
|
|
313
326
|
actualBoundingBoxDescent: metrics.actualBoundingBoxDescent || 0,
|
|
@@ -321,6 +334,15 @@ class WebGLCanvasAdapter {
|
|
|
321
334
|
hangingBaseline: metrics.hangingBaseline || 0,
|
|
322
335
|
ideographicBaseline: metrics.ideographicBaseline || 0
|
|
323
336
|
};
|
|
337
|
+
|
|
338
|
+
// ✅ Cache avec limite
|
|
339
|
+
if (this.measureTextCache.size >= 200) {
|
|
340
|
+
const firstKey = this.measureTextCache.keys().next().value;
|
|
341
|
+
this.measureTextCache.delete(firstKey);
|
|
342
|
+
}
|
|
343
|
+
this.measureTextCache.set(cacheKey, result);
|
|
344
|
+
|
|
345
|
+
return result;
|
|
324
346
|
}
|
|
325
347
|
|
|
326
348
|
// --- Paths ---
|
|
@@ -860,6 +882,21 @@ class WebGLCanvasAdapter {
|
|
|
860
882
|
this.solidProgram = this.createProgram(vsSolidSource, fsSolidSource);
|
|
861
883
|
this.textureProgram = this.createProgram(vsTextureSource, fsTextureSource);
|
|
862
884
|
|
|
885
|
+
// ✅ CACHE DES UNIFORM LOCATIONS
|
|
886
|
+
this.uniformLocations = {
|
|
887
|
+
solid: {
|
|
888
|
+
projection: this.gl.getUniformLocation(this.solidProgram, 'uProjectionMatrix'),
|
|
889
|
+
transform: this.gl.getUniformLocation(this.solidProgram, 'uTransformMatrix')
|
|
890
|
+
},
|
|
891
|
+
texture: {
|
|
892
|
+
projection: this.gl.getUniformLocation(this.textureProgram, 'uProjectionMatrix'),
|
|
893
|
+
transform: this.gl.getUniformLocation(this.textureProgram, 'uTransformMatrix'),
|
|
894
|
+
alpha: this.gl.getUniformLocation(this.textureProgram, 'uAlpha'),
|
|
895
|
+
tintColor: this.gl.getUniformLocation(this.textureProgram, 'uTintColor'),
|
|
896
|
+
texture: this.gl.getUniformLocation(this.textureProgram, 'uTexture')
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
|
|
863
900
|
// Buffers
|
|
864
901
|
this.positionBuffer = gl.createBuffer();
|
|
865
902
|
this.colorBuffer = gl.createBuffer();
|
|
@@ -954,13 +991,13 @@ class WebGLCanvasAdapter {
|
|
|
954
991
|
gl.bindVertexArray(this.solidVAO);
|
|
955
992
|
|
|
956
993
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
|
|
957
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.vertices), gl.
|
|
994
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.vertices), gl.DYNAMIC_DRAW);
|
|
958
995
|
|
|
959
996
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
|
|
960
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.colors), gl.
|
|
997
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.colors), gl.DYNAMIC_DRAW);
|
|
961
998
|
|
|
962
|
-
|
|
963
|
-
|
|
999
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.projection, false, this.projectionMatrix);
|
|
1000
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.transform, false, new Float32Array(this.state.transform));
|
|
964
1001
|
|
|
965
1002
|
const transformLoc = gl.getUniformLocation(this.solidProgram, 'uTransformMatrix');
|
|
966
1003
|
gl.uniformMatrix3fv(transformLoc, false, new Float32Array(this.state.transform));
|
|
@@ -976,13 +1013,13 @@ class WebGLCanvasAdapter {
|
|
|
976
1013
|
gl.bindVertexArray(this.textureVAO);
|
|
977
1014
|
|
|
978
1015
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
|
|
979
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.textureVertices), gl.
|
|
1016
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.textureVertices), gl.DYNAMIC_DRAW);
|
|
980
1017
|
|
|
981
1018
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
|
|
982
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.textureTexCoords), gl.
|
|
1019
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.textureTexCoords), gl.DYNAMIC_DRAW);
|
|
983
1020
|
|
|
984
|
-
|
|
985
|
-
|
|
1021
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.projection, false, this.projectionMatrix);
|
|
1022
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.transform, false, new Float32Array(this.state.transform));
|
|
986
1023
|
|
|
987
1024
|
const transformLoc = gl.getUniformLocation(this.textureProgram, 'uTransformMatrix');
|
|
988
1025
|
gl.uniformMatrix3fv(transformLoc, false, new Float32Array(this.state.transform));
|
|
@@ -1033,8 +1070,8 @@ class WebGLCanvasAdapter {
|
|
|
1033
1070
|
gl.enableVertexAttribArray(colorLoc);
|
|
1034
1071
|
gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
|
|
1035
1072
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1073
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.projection, false, this.projectionMatrix);
|
|
1074
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.transform, false, new Float32Array(this.state.transform));
|
|
1038
1075
|
|
|
1039
1076
|
const transformLoc = gl.getUniformLocation(this.solidProgram, 'uTransformMatrix');
|
|
1040
1077
|
gl.uniformMatrix3fv(transformLoc, false, new Float32Array(this.state.transform));
|
|
@@ -1099,8 +1136,8 @@ class WebGLCanvasAdapter {
|
|
|
1099
1136
|
gl.enableVertexAttribArray(texLoc);
|
|
1100
1137
|
gl.vertexAttribPointer(texLoc, 2, gl.FLOAT, false, 0, 0);
|
|
1101
1138
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1139
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.projection, false, this.projectionMatrix);
|
|
1140
|
+
gl.uniformMatrix3fv(this.uniformLocations.solid.transform, false, new Float32Array(this.state.transform));
|
|
1104
1141
|
|
|
1105
1142
|
const transformLoc = gl.getUniformLocation(this.textureProgram, 'uTransformMatrix');
|
|
1106
1143
|
gl.uniformMatrix3fv(transformLoc, false, new Float32Array(this.state.transform));
|
|
@@ -1194,7 +1231,12 @@ class WebGLCanvasAdapter {
|
|
|
1194
1231
|
return [0, 0, 0, 1];
|
|
1195
1232
|
}
|
|
1196
1233
|
|
|
1197
|
-
|
|
1234
|
+
// ✅ AJOUTER CACHE LOOKUP
|
|
1235
|
+
if (this.colorCache.has(color)) {
|
|
1236
|
+
return this.colorCache.get(color);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
if (color._id && this.gradients.has(color._id)) {
|
|
1198
1240
|
return [0, 0, 0, 1];
|
|
1199
1241
|
}
|
|
1200
1242
|
|
|
@@ -1243,6 +1285,13 @@ class WebGLCanvasAdapter {
|
|
|
1243
1285
|
'cyan': [0, 1, 1, 1], 'magenta': [1, 0, 1, 1], 'gray': [0.5, 0.5, 0.5, 1],
|
|
1244
1286
|
'grey': [0.5, 0.5, 0.5, 1], 'transparent': [0, 0, 0, 0]
|
|
1245
1287
|
};
|
|
1288
|
+
|
|
1289
|
+
// ✅ AVANT LE RETURN FINAL, AJOUTER :
|
|
1290
|
+
if (this.colorCache.size >= this.colorCacheMaxSize) {
|
|
1291
|
+
const firstKey = this.colorCache.keys().next().value;
|
|
1292
|
+
this.colorCache.delete(firstKey);
|
|
1293
|
+
}
|
|
1294
|
+
this.colorCache.set(color, result); // result = le tableau [r,g,b,a]
|
|
1246
1295
|
|
|
1247
1296
|
return namedColors[color.toLowerCase()] || [0, 0, 0, 1];
|
|
1248
1297
|
}
|