opencroc 1.4.2 → 1.4.3

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/dist/web/index.html +44 -13
  2. package/package.json +1 -1
@@ -201,36 +201,67 @@ function layoutGraph(){
201
201
  const w=c.clientWidth||800,h=c.clientHeight||500;
202
202
  // Group non-module nodes by module
203
203
  const mods=new Map();
204
- S.modMeta=new Map(); // module → {cx,cy,radius,color}
204
+ S.modMeta=new Map();
205
205
  for(const n of nodes){
206
206
  if(n.type==='module') continue;
207
207
  const m=n.module||'other';
208
208
  if(!mods.has(m)) mods.set(m,[]);
209
209
  mods.get(m).push(n);
210
210
  }
211
+ // Sort by size descending
211
212
  const keys=[...mods.keys()].sort((a,b)=>(mods.get(b).length-mods.get(a).length));
212
213
  const nMods=keys.length||1;
213
- // Module color palette (10 distinct colors, cycle)
214
214
  const palette=['#4ecca3','#e94560','#f39c12','#3498db','#9b59b6','#1abc9c','#e67e22','#2ecc71','#e84393','#00cec9'];
215
- // Adaptive ring radius
216
- const totalMembers=nodes.filter(n=>n.type!=='module').length;
217
- const baseRadius=Math.max(300, Math.sqrt(totalMembers)*30);
215
+ const RING_CAP=24; // max nodes per ring layer
216
+
217
+ // Calculate each module's outer radius (for spacing)
218
+ const modRadii=[];
219
+ for(let i=0;i<keys.length;i++){
220
+ const cnt=mods.get(keys[i]).length;
221
+ const rings=Math.ceil(cnt/RING_CAP);
222
+ const outerR=rings===1?Math.max(40,cnt*6):rings*32+20;
223
+ modRadii.push(outerR);
224
+ }
225
+
226
+ // Adaptive base ring: sum of all module diameters / (2*PI) gives minimum perimeter
227
+ const totalDiam=modRadii.reduce((s,r)=>s+r*2+60,0); // 60px gap between modules
228
+ const baseRadius=Math.max(400, totalDiam/(Math.PI*2));
229
+
230
+ // Place modules with angular spacing proportional to their size
231
+ const totalWeight=modRadii.reduce((s,r)=>s+r+30,0);
232
+ let angle=-Math.PI/2;
218
233
  for(let i=0;i<keys.length;i++){
219
234
  const mn=mods.get(keys[i]); if(!mn)continue;
220
- const modAngle=(i/nMods)*Math.PI*2-Math.PI/2;
235
+ const cnt=mn.length;
236
+ const col=palette[i%palette.length];
237
+ const rings=Math.ceil(cnt/RING_CAP);
238
+ const outerR=modRadii[i];
239
+
240
+ // Angular span for this module proportional to its size
241
+ const span=((outerR+30)/totalWeight)*Math.PI*2;
242
+ const modAngle=angle+span/2;
243
+ angle+=span;
244
+
221
245
  const mcx=w/2+Math.cos(modAngle)*baseRadius;
222
246
  const mcy=h/2+Math.sin(modAngle)*baseRadius;
223
- const subRadius=Math.max(50, Math.sqrt(mn.length)*22);
224
- const col=palette[i%palette.length];
225
- // Store module meta for cluster rendering
247
+
226
248
  const modNodeId='module:'+keys[i];
227
249
  S.nodePos.set(modNodeId,{x:mcx,y:mcy});
228
- S.modMeta.set(keys[i],{cx:mcx,cy:mcy,radius:subRadius+30,color:col,count:mn.length});
229
- for(let j=0;j<mn.length;j++){
230
- const na=(j/mn.length)*Math.PI*2;
231
- S.nodePos.set(mn[j].id,{x:mcx+Math.cos(na)*subRadius,y:mcy+Math.sin(na)*subRadius});
250
+ S.modMeta.set(keys[i],{cx:mcx,cy:mcy,radius:outerR+20,color:col,count:cnt});
251
+
252
+ // Spread nodes across concentric rings
253
+ let placed=0;
254
+ for(let ring=0;ring<rings;ring++){
255
+ const nodesInRing=Math.min(RING_CAP,cnt-placed);
256
+ const r=rings===1?Math.max(40,nodesInRing*6):(ring+1)*32;
257
+ for(let j=0;j<nodesInRing;j++){
258
+ const na=(j/nodesInRing)*Math.PI*2;
259
+ S.nodePos.set(mn[placed].id,{x:mcx+Math.cos(na)*r,y:mcy+Math.sin(na)*r});
260
+ placed++;
261
+ }
232
262
  }
233
263
  }
264
+
234
265
  // Auto-center
235
266
  if(nodes.length>0&&!S._userPanned){
236
267
  let minX=Infinity,maxX=-Infinity,minY=Infinity,maxY=-Infinity;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencroc",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "AI-native E2E testing framework — source-aware test generation, intelligent validation, and self-healing",
5
5
  "keywords": [
6
6
  "e2e",