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 = '#6200EE';
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 = '#000000';
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}`,
@@ -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
- return Math.max(0, maxY - this.height + 50);
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
- // Pour WebGL, NE PAS redimensionner automatiquement
1255
- if (!this.useWebGL) {
1256
- this.width = window.innerWidth;
1257
- this.height = window.innerHeight;
1258
- this.setupCanvas();
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
- for (const comp of this.components) {
1261
- if (comp._resize) {
1262
- comp._resize(this.width, this.height);
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
- component._mount();
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
- component._unmount();
1278
- this.components.splice(index, 1);
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
- this.ctx.save();
1501
- this.ctx.translate(0, this.scrollOffset);
1502
- for (let comp of scrollableComponents) {
1503
- if (comp.visible) {
1504
- comp.draw(this.ctx);
1505
- }
1506
- }
1507
- this.ctx.restore();
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
- return {
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.STATIC_DRAW);
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.STATIC_DRAW);
997
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.colors), gl.DYNAMIC_DRAW);
961
998
 
962
- const projLoc = gl.getUniformLocation(this.solidProgram, 'uProjectionMatrix');
963
- gl.uniformMatrix3fv(projLoc, false, this.projectionMatrix);
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.STATIC_DRAW);
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.STATIC_DRAW);
1019
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.batch.textureTexCoords), gl.DYNAMIC_DRAW);
983
1020
 
984
- const projLoc = gl.getUniformLocation(this.textureProgram, 'uProjectionMatrix');
985
- gl.uniformMatrix3fv(projLoc, false, this.projectionMatrix);
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
- const projLoc = gl.getUniformLocation(this.solidProgram, 'uProjectionMatrix');
1037
- gl.uniformMatrix3fv(projLoc, false, this.projectionMatrix);
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
- const projLoc = gl.getUniformLocation(this.textureProgram, 'uProjectionMatrix');
1103
- gl.uniformMatrix3fv(projLoc, false, this.projectionMatrix);
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
- if (color._id && this.gradients.has(color._id)) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.3.29",
3
+ "version": "0.4.1",
4
4
  "description": "Canvas-based cross-platform UI framework (Material & Cupertino)",
5
5
  "type": "module",
6
6
  "main": "./index.js",