@cadview/core 0.2.0 → 0.3.0
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/dist/index.cjs +321 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -3
- package/dist/index.d.ts +77 -3
- package/dist/index.js +321 -14
- package/dist/index.js.map +1 -1
- package/package.json +25 -12
package/dist/index.js
CHANGED
|
@@ -2691,7 +2691,7 @@ function drawMText(ctx, entity, pixelSize) {
|
|
|
2691
2691
|
|
|
2692
2692
|
// src/renderer/entities/draw-insert.ts
|
|
2693
2693
|
var MAX_INSERT_DEPTH = 100;
|
|
2694
|
-
function drawInsert(ctx, entity, doc, vt, theme, pixelSize, depth = 0) {
|
|
2694
|
+
function drawInsert(ctx, entity, doc, vt, theme, pixelSize, depth = 0, stats) {
|
|
2695
2695
|
if (depth > MAX_INSERT_DEPTH) return;
|
|
2696
2696
|
const block = doc.blocks.get(entity.blockName);
|
|
2697
2697
|
if (!block) return;
|
|
@@ -2716,9 +2716,9 @@ function drawInsert(ctx, entity, doc, vt, theme, pixelSize, depth = 0) {
|
|
|
2716
2716
|
ctx.fillStyle = color;
|
|
2717
2717
|
ctx.lineWidth = adjustedPixelSize;
|
|
2718
2718
|
if (blockEntity.type === "INSERT") {
|
|
2719
|
-
drawInsert(ctx, blockEntity, doc, vt, theme, adjustedPixelSize, depth + 1);
|
|
2719
|
+
drawInsert(ctx, blockEntity, doc, vt, theme, adjustedPixelSize, depth + 1, stats);
|
|
2720
2720
|
} else {
|
|
2721
|
-
drawEntity(ctx, blockEntity, doc, vt, theme, adjustedPixelSize);
|
|
2721
|
+
drawEntity(ctx, blockEntity, doc, vt, theme, adjustedPixelSize, stats);
|
|
2722
2722
|
}
|
|
2723
2723
|
}
|
|
2724
2724
|
ctx.restore();
|
|
@@ -2727,7 +2727,7 @@ function drawInsert(ctx, entity, doc, vt, theme, pixelSize, depth = 0) {
|
|
|
2727
2727
|
}
|
|
2728
2728
|
|
|
2729
2729
|
// src/renderer/entities/draw-dimension.ts
|
|
2730
|
-
function drawDimension(ctx, entity, doc, vt, theme, pixelSize) {
|
|
2730
|
+
function drawDimension(ctx, entity, doc, vt, theme, pixelSize, stats) {
|
|
2731
2731
|
if (entity.blockName) {
|
|
2732
2732
|
const block = doc.blocks.get(entity.blockName);
|
|
2733
2733
|
if (block) {
|
|
@@ -2736,7 +2736,7 @@ function drawDimension(ctx, entity, doc, vt, theme, pixelSize) {
|
|
|
2736
2736
|
ctx.strokeStyle = color;
|
|
2737
2737
|
ctx.fillStyle = color;
|
|
2738
2738
|
ctx.lineWidth = pixelSize;
|
|
2739
|
-
drawEntity(ctx, blockEntity, doc, vt, theme, pixelSize);
|
|
2739
|
+
drawEntity(ctx, blockEntity, doc, vt, theme, pixelSize, stats);
|
|
2740
2740
|
}
|
|
2741
2741
|
return;
|
|
2742
2742
|
}
|
|
@@ -2813,7 +2813,11 @@ function drawPoint(ctx, entity, pixelSize) {
|
|
|
2813
2813
|
}
|
|
2814
2814
|
|
|
2815
2815
|
// src/renderer/entities/draw-entity.ts
|
|
2816
|
-
function drawEntity(ctx, entity, doc, vt, theme, pixelSize) {
|
|
2816
|
+
function drawEntity(ctx, entity, doc, vt, theme, pixelSize, stats) {
|
|
2817
|
+
if (stats) {
|
|
2818
|
+
stats.drawCalls++;
|
|
2819
|
+
stats.byType[entity.type] = (stats.byType[entity.type] ?? 0) + 1;
|
|
2820
|
+
}
|
|
2817
2821
|
switch (entity.type) {
|
|
2818
2822
|
case "LINE":
|
|
2819
2823
|
drawLine(ctx, entity);
|
|
@@ -2843,10 +2847,10 @@ function drawEntity(ctx, entity, doc, vt, theme, pixelSize) {
|
|
|
2843
2847
|
drawMText(ctx, entity, pixelSize);
|
|
2844
2848
|
break;
|
|
2845
2849
|
case "INSERT":
|
|
2846
|
-
drawInsert(ctx, entity, doc, vt, theme, pixelSize);
|
|
2850
|
+
drawInsert(ctx, entity, doc, vt, theme, pixelSize, 0, stats);
|
|
2847
2851
|
break;
|
|
2848
2852
|
case "DIMENSION":
|
|
2849
|
-
drawDimension(ctx, entity, doc, vt, theme, pixelSize);
|
|
2853
|
+
drawDimension(ctx, entity, doc, vt, theme, pixelSize, stats);
|
|
2850
2854
|
break;
|
|
2851
2855
|
case "HATCH":
|
|
2852
2856
|
drawHatch(ctx, entity);
|
|
@@ -2893,6 +2897,12 @@ var CanvasRenderer = class {
|
|
|
2893
2897
|
render(doc, vt, theme, visibleLayers, selectedEntityIndex) {
|
|
2894
2898
|
const ctx = this.ctx;
|
|
2895
2899
|
const dpr = window.devicePixelRatio || 1;
|
|
2900
|
+
const stats = {
|
|
2901
|
+
entitiesDrawn: 0,
|
|
2902
|
+
entitiesSkipped: 0,
|
|
2903
|
+
drawCalls: 0,
|
|
2904
|
+
byType: {}
|
|
2905
|
+
};
|
|
2896
2906
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
2897
2907
|
ctx.fillStyle = THEMES[theme].backgroundColor;
|
|
2898
2908
|
ctx.fillRect(0, 0, this.width, this.height);
|
|
@@ -2902,13 +2912,20 @@ var CanvasRenderer = class {
|
|
|
2902
2912
|
ctx.lineJoin = "round";
|
|
2903
2913
|
for (let i = 0; i < doc.entities.length; i++) {
|
|
2904
2914
|
const entity = doc.entities[i];
|
|
2905
|
-
if (!entity.visible)
|
|
2906
|
-
|
|
2915
|
+
if (!entity.visible) {
|
|
2916
|
+
stats.entitiesSkipped++;
|
|
2917
|
+
continue;
|
|
2918
|
+
}
|
|
2919
|
+
if (!visibleLayers.has(entity.layer)) {
|
|
2920
|
+
stats.entitiesSkipped++;
|
|
2921
|
+
continue;
|
|
2922
|
+
}
|
|
2907
2923
|
const color = resolveEntityColor(entity, doc.layers, theme);
|
|
2908
2924
|
ctx.strokeStyle = color;
|
|
2909
2925
|
ctx.fillStyle = color;
|
|
2910
2926
|
ctx.lineWidth = pixelSize;
|
|
2911
|
-
|
|
2927
|
+
stats.entitiesDrawn++;
|
|
2928
|
+
drawEntity(ctx, entity, doc, vt, theme, pixelSize, stats);
|
|
2912
2929
|
}
|
|
2913
2930
|
if (selectedEntityIndex >= 0 && selectedEntityIndex < doc.entities.length) {
|
|
2914
2931
|
const selEntity = doc.entities[selectedEntityIndex];
|
|
@@ -2918,6 +2935,7 @@ var CanvasRenderer = class {
|
|
|
2918
2935
|
ctx.lineWidth = pixelSize * 3;
|
|
2919
2936
|
drawEntity(ctx, selEntity, doc, vt, theme, pixelSize);
|
|
2920
2937
|
}
|
|
2938
|
+
return stats;
|
|
2921
2939
|
}
|
|
2922
2940
|
renderEmpty(theme) {
|
|
2923
2941
|
const ctx = this.ctx;
|
|
@@ -2930,6 +2948,136 @@ var CanvasRenderer = class {
|
|
|
2930
2948
|
}
|
|
2931
2949
|
};
|
|
2932
2950
|
|
|
2951
|
+
// src/renderer/debug-overlay.ts
|
|
2952
|
+
var DEFAULT_DEBUG_OPTIONS = {
|
|
2953
|
+
showFps: true,
|
|
2954
|
+
showRenderStats: true,
|
|
2955
|
+
showDocumentInfo: true,
|
|
2956
|
+
showTimings: true,
|
|
2957
|
+
showCamera: true,
|
|
2958
|
+
position: "top-left"
|
|
2959
|
+
};
|
|
2960
|
+
function resolveDebugOptions(input) {
|
|
2961
|
+
return { ...DEFAULT_DEBUG_OPTIONS, ...input };
|
|
2962
|
+
}
|
|
2963
|
+
function formatBytes(bytes) {
|
|
2964
|
+
if (bytes === 0) return "0 B";
|
|
2965
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
2966
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2967
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2968
|
+
}
|
|
2969
|
+
function formatZoom(scale) {
|
|
2970
|
+
if (scale >= 1) return `${scale.toFixed(2)}x`;
|
|
2971
|
+
return `1:${(1 / scale).toFixed(1)}`;
|
|
2972
|
+
}
|
|
2973
|
+
var FONT = "11px monospace";
|
|
2974
|
+
var LINE_HEIGHT = 15;
|
|
2975
|
+
var SEPARATOR_HEIGHT = 8;
|
|
2976
|
+
var PADDING = 8;
|
|
2977
|
+
var MARGIN = 10;
|
|
2978
|
+
function renderDebugOverlay(ctx, stats, theme, options, canvasWidth, canvasHeight) {
|
|
2979
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
2980
|
+
const sections = [];
|
|
2981
|
+
if (options.showFps) {
|
|
2982
|
+
sections.push([
|
|
2983
|
+
`FPS: ${stats.fps} Frame: ${stats.frameTime.toFixed(1)}ms`
|
|
2984
|
+
]);
|
|
2985
|
+
}
|
|
2986
|
+
if (options.showRenderStats) {
|
|
2987
|
+
const total = stats.renderStats.entitiesDrawn + stats.renderStats.entitiesSkipped;
|
|
2988
|
+
const lines = [
|
|
2989
|
+
`Drawn: ${stats.renderStats.entitiesDrawn} / ${total} Calls: ${stats.renderStats.drawCalls}`
|
|
2990
|
+
];
|
|
2991
|
+
const types = Object.entries(stats.renderStats.byType).sort(([, a], [, b]) => b - a).slice(0, 6).map(([type, count]) => `${type}: ${count}`).join(" ");
|
|
2992
|
+
if (types) lines.push(types);
|
|
2993
|
+
sections.push(lines);
|
|
2994
|
+
}
|
|
2995
|
+
if (options.showDocumentInfo) {
|
|
2996
|
+
const lines = [
|
|
2997
|
+
`Layers: ${stats.visibleLayerCount} / ${stats.layerCount} Blocks: ${stats.blockCount}`
|
|
2998
|
+
];
|
|
2999
|
+
if (stats.dxfVersion) lines.push(`DXF: ${stats.dxfVersion}`);
|
|
3000
|
+
if (stats.fileName) lines.push(`File: ${stats.fileName}`);
|
|
3001
|
+
if (stats.fileSize > 0) lines.push(`Size: ${formatBytes(stats.fileSize)}`);
|
|
3002
|
+
sections.push(lines);
|
|
3003
|
+
}
|
|
3004
|
+
if (options.showTimings) {
|
|
3005
|
+
const parts = [];
|
|
3006
|
+
if (stats.parseTime > 0) parts.push(`Parse: ${stats.parseTime.toFixed(0)}ms`);
|
|
3007
|
+
if (stats.spatialIndexBuildTime > 0) parts.push(`Index: ${stats.spatialIndexBuildTime.toFixed(0)}ms`);
|
|
3008
|
+
if (stats.totalLoadTime > 0) parts.push(`Load: ${stats.totalLoadTime.toFixed(0)}ms`);
|
|
3009
|
+
if (parts.length > 0) {
|
|
3010
|
+
sections.push([parts.join(" ")]);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
if (options.showCamera) {
|
|
3014
|
+
const b = stats.viewportBounds;
|
|
3015
|
+
sections.push([
|
|
3016
|
+
`Zoom: ${formatZoom(stats.zoom)} Pixel: ${stats.pixelSize.toFixed(2)}`,
|
|
3017
|
+
`View: [${b.minX.toFixed(0)}, ${b.minY.toFixed(0)}] \u2192 [${b.maxX.toFixed(0)}, ${b.maxY.toFixed(0)}]`
|
|
3018
|
+
]);
|
|
3019
|
+
}
|
|
3020
|
+
if (sections.length === 0) return;
|
|
3021
|
+
ctx.font = FONT;
|
|
3022
|
+
const rows = [];
|
|
3023
|
+
for (let s = 0; s < sections.length; s++) {
|
|
3024
|
+
if (s > 0) rows.push({ text: "", isSeparator: true });
|
|
3025
|
+
for (const line of sections[s]) {
|
|
3026
|
+
rows.push({ text: line, isSeparator: false });
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
let maxWidth = 0;
|
|
3030
|
+
for (const row of rows) {
|
|
3031
|
+
if (!row.isSeparator) {
|
|
3032
|
+
const w = ctx.measureText(row.text).width;
|
|
3033
|
+
if (w > maxWidth) maxWidth = w;
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
const panelWidth = maxWidth + PADDING * 2;
|
|
3037
|
+
let panelHeight = PADDING * 2;
|
|
3038
|
+
for (const row of rows) {
|
|
3039
|
+
panelHeight += row.isSeparator ? SEPARATOR_HEIGHT : LINE_HEIGHT;
|
|
3040
|
+
}
|
|
3041
|
+
let x;
|
|
3042
|
+
let y;
|
|
3043
|
+
switch (options.position) {
|
|
3044
|
+
case "top-left":
|
|
3045
|
+
x = MARGIN;
|
|
3046
|
+
y = MARGIN;
|
|
3047
|
+
break;
|
|
3048
|
+
case "top-right":
|
|
3049
|
+
x = canvasWidth - panelWidth - MARGIN;
|
|
3050
|
+
y = MARGIN;
|
|
3051
|
+
break;
|
|
3052
|
+
case "bottom-left":
|
|
3053
|
+
x = MARGIN;
|
|
3054
|
+
y = canvasHeight - panelHeight - MARGIN;
|
|
3055
|
+
break;
|
|
3056
|
+
case "bottom-right":
|
|
3057
|
+
x = canvasWidth - panelWidth - MARGIN;
|
|
3058
|
+
y = canvasHeight - panelHeight - MARGIN;
|
|
3059
|
+
break;
|
|
3060
|
+
}
|
|
3061
|
+
const config = THEMES[theme];
|
|
3062
|
+
ctx.fillStyle = theme === "dark" ? "rgba(0, 0, 0, 0.75)" : "rgba(255, 255, 255, 0.85)";
|
|
3063
|
+
ctx.fillRect(x, y, panelWidth, panelHeight);
|
|
3064
|
+
ctx.strokeStyle = theme === "dark" ? "rgba(255, 255, 255, 0.15)" : "rgba(0, 0, 0, 0.15)";
|
|
3065
|
+
ctx.lineWidth = 1;
|
|
3066
|
+
ctx.strokeRect(x + 0.5, y + 0.5, panelWidth - 1, panelHeight - 1);
|
|
3067
|
+
ctx.fillStyle = theme === "dark" ? config.defaultEntityColor : "rgba(0, 0, 0, 0.85)";
|
|
3068
|
+
ctx.textAlign = "left";
|
|
3069
|
+
ctx.textBaseline = "top";
|
|
3070
|
+
let cursorY = y + PADDING;
|
|
3071
|
+
for (const row of rows) {
|
|
3072
|
+
if (row.isSeparator) {
|
|
3073
|
+
cursorY += SEPARATOR_HEIGHT;
|
|
3074
|
+
} else {
|
|
3075
|
+
ctx.fillText(row.text, x + PADDING, cursorY);
|
|
3076
|
+
cursorY += LINE_HEIGHT;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
|
|
2933
3081
|
// src/viewer/layers.ts
|
|
2934
3082
|
var LayerManager = class {
|
|
2935
3083
|
layers = /* @__PURE__ */ new Map();
|
|
@@ -3720,6 +3868,19 @@ var CadViewer = class {
|
|
|
3720
3868
|
loadGeneration = 0;
|
|
3721
3869
|
mouseScreenX = 0;
|
|
3722
3870
|
mouseScreenY = 0;
|
|
3871
|
+
// Debug mode state
|
|
3872
|
+
debugEnabled = false;
|
|
3873
|
+
debugOptions;
|
|
3874
|
+
lastRenderStats = null;
|
|
3875
|
+
lastDebugStats = null;
|
|
3876
|
+
frameTimestamps = [];
|
|
3877
|
+
lastDoRenderTime = 0;
|
|
3878
|
+
lastFrameTime = 0;
|
|
3879
|
+
parseTime = 0;
|
|
3880
|
+
spatialIndexBuildTime = 0;
|
|
3881
|
+
loadedFileName = null;
|
|
3882
|
+
loadedFileSize = 0;
|
|
3883
|
+
debugRafId = 0;
|
|
3723
3884
|
constructor(canvas, options) {
|
|
3724
3885
|
this.canvas = canvas;
|
|
3725
3886
|
this.options = {
|
|
@@ -3732,6 +3893,14 @@ var CadViewer = class {
|
|
|
3732
3893
|
initialTool: options?.initialTool ?? "pan"
|
|
3733
3894
|
};
|
|
3734
3895
|
this.formatConverters = options?.formatConverters ?? [];
|
|
3896
|
+
if (options?.debug) {
|
|
3897
|
+
this.debugEnabled = true;
|
|
3898
|
+
this.debugOptions = resolveDebugOptions(
|
|
3899
|
+
typeof options.debug === "boolean" ? void 0 : options.debug
|
|
3900
|
+
);
|
|
3901
|
+
} else {
|
|
3902
|
+
this.debugOptions = resolveDebugOptions();
|
|
3903
|
+
}
|
|
3735
3904
|
this.renderer = new CanvasRenderer(canvas);
|
|
3736
3905
|
this.camera = new Camera(this.options);
|
|
3737
3906
|
this.layerManager = new LayerManager();
|
|
@@ -3744,6 +3913,9 @@ var CadViewer = class {
|
|
|
3744
3913
|
this.resizeObserver.observe(canvas);
|
|
3745
3914
|
canvas.style.cursor = this.getCursorForTool(this.currentTool);
|
|
3746
3915
|
this.requestRender();
|
|
3916
|
+
if (this.debugEnabled) {
|
|
3917
|
+
this.startDebugLoop();
|
|
3918
|
+
}
|
|
3747
3919
|
}
|
|
3748
3920
|
// === Loading ===
|
|
3749
3921
|
/**
|
|
@@ -3782,11 +3954,15 @@ var CadViewer = class {
|
|
|
3782
3954
|
async loadFile(file) {
|
|
3783
3955
|
this.guardDestroyed();
|
|
3784
3956
|
const generation = ++this.loadGeneration;
|
|
3957
|
+
this.loadedFileName = file.name;
|
|
3958
|
+
this.loadedFileSize = file.size;
|
|
3785
3959
|
const buffer = await file.arrayBuffer();
|
|
3786
3960
|
if (this.destroyed || generation !== this.loadGeneration) return;
|
|
3787
3961
|
const dxfString = await this.runConverters(buffer);
|
|
3788
3962
|
if (this.destroyed || generation !== this.loadGeneration) return;
|
|
3963
|
+
const t0 = performance.now();
|
|
3789
3964
|
this.doc = dxfString != null ? parseDxf(dxfString) : parseDxf(buffer);
|
|
3965
|
+
this.parseTime = performance.now() - t0;
|
|
3790
3966
|
this.onDocumentLoaded();
|
|
3791
3967
|
}
|
|
3792
3968
|
/**
|
|
@@ -3797,9 +3973,13 @@ var CadViewer = class {
|
|
|
3797
3973
|
async loadBuffer(buffer) {
|
|
3798
3974
|
this.guardDestroyed();
|
|
3799
3975
|
const generation = ++this.loadGeneration;
|
|
3976
|
+
this.loadedFileName = null;
|
|
3977
|
+
this.loadedFileSize = buffer.byteLength;
|
|
3800
3978
|
const dxfString = await this.runConverters(buffer);
|
|
3801
3979
|
if (this.destroyed || generation !== this.loadGeneration) return;
|
|
3980
|
+
const t0 = performance.now();
|
|
3802
3981
|
this.doc = dxfString != null ? parseDxf(dxfString) : parseDxf(buffer);
|
|
3982
|
+
this.parseTime = performance.now() - t0;
|
|
3803
3983
|
this.onDocumentLoaded();
|
|
3804
3984
|
}
|
|
3805
3985
|
/**
|
|
@@ -3809,6 +3989,9 @@ var CadViewer = class {
|
|
|
3809
3989
|
loadDocument(doc) {
|
|
3810
3990
|
this.guardDestroyed();
|
|
3811
3991
|
++this.loadGeneration;
|
|
3992
|
+
this.loadedFileName = null;
|
|
3993
|
+
this.loadedFileSize = 0;
|
|
3994
|
+
this.parseTime = 0;
|
|
3812
3995
|
if (!doc || !Array.isArray(doc.entities) || !(doc.layers instanceof Map)) {
|
|
3813
3996
|
throw new Error("CadViewer: invalid DxfDocument \u2014 expected entities array and layers Map.");
|
|
3814
3997
|
}
|
|
@@ -3821,7 +4004,11 @@ var CadViewer = class {
|
|
|
3821
4004
|
loadString(dxf) {
|
|
3822
4005
|
this.guardDestroyed();
|
|
3823
4006
|
++this.loadGeneration;
|
|
4007
|
+
this.loadedFileName = null;
|
|
4008
|
+
this.loadedFileSize = dxf.length;
|
|
4009
|
+
const t0 = performance.now();
|
|
3824
4010
|
this.doc = parseDxf(dxf);
|
|
4011
|
+
this.parseTime = performance.now() - t0;
|
|
3825
4012
|
this.onDocumentLoaded();
|
|
3826
4013
|
}
|
|
3827
4014
|
/**
|
|
@@ -3831,7 +4018,11 @@ var CadViewer = class {
|
|
|
3831
4018
|
loadArrayBuffer(buffer) {
|
|
3832
4019
|
this.guardDestroyed();
|
|
3833
4020
|
++this.loadGeneration;
|
|
4021
|
+
this.loadedFileName = null;
|
|
4022
|
+
this.loadedFileSize = buffer.byteLength;
|
|
4023
|
+
const t0 = performance.now();
|
|
3834
4024
|
this.doc = parseDxf(buffer);
|
|
4025
|
+
this.parseTime = performance.now() - t0;
|
|
3835
4026
|
this.onDocumentLoaded();
|
|
3836
4027
|
}
|
|
3837
4028
|
/**
|
|
@@ -3850,7 +4041,9 @@ var CadViewer = class {
|
|
|
3850
4041
|
onDocumentLoaded() {
|
|
3851
4042
|
if (!this.doc) return;
|
|
3852
4043
|
this.layerManager.setLayers(this.doc.layers);
|
|
4044
|
+
const t0 = performance.now();
|
|
3853
4045
|
this.spatialIndex.build(this.doc.entities);
|
|
4046
|
+
this.spatialIndexBuildTime = performance.now() - t0;
|
|
3854
4047
|
this.selectedEntityIndex = -1;
|
|
3855
4048
|
this.measureTool.deactivate();
|
|
3856
4049
|
if (this.currentTool === "measure") {
|
|
@@ -3978,6 +4171,7 @@ var CadViewer = class {
|
|
|
3978
4171
|
}
|
|
3979
4172
|
destroy() {
|
|
3980
4173
|
this.destroyed = true;
|
|
4174
|
+
this.stopDebugLoop();
|
|
3981
4175
|
this.inputHandler.destroy();
|
|
3982
4176
|
this.resizeObserver.disconnect();
|
|
3983
4177
|
this.renderer.destroy();
|
|
@@ -3989,7 +4183,12 @@ var CadViewer = class {
|
|
|
3989
4183
|
// === Internal (called by InputHandler) ===
|
|
3990
4184
|
/** @internal */
|
|
3991
4185
|
requestRender() {
|
|
3992
|
-
if (this.
|
|
4186
|
+
if (this.destroyed) return;
|
|
4187
|
+
if (this.debugRafId) {
|
|
4188
|
+
this.doRender();
|
|
4189
|
+
return;
|
|
4190
|
+
}
|
|
4191
|
+
if (this.renderPending) return;
|
|
3993
4192
|
this.renderPending = true;
|
|
3994
4193
|
requestAnimationFrame(() => {
|
|
3995
4194
|
this.renderPending = false;
|
|
@@ -4002,13 +4201,24 @@ var CadViewer = class {
|
|
|
4002
4201
|
this.renderer.renderEmpty(this.options.theme);
|
|
4003
4202
|
return;
|
|
4004
4203
|
}
|
|
4005
|
-
|
|
4204
|
+
const renderStart = performance.now();
|
|
4205
|
+
const stats = this.renderer.render(
|
|
4006
4206
|
this.doc,
|
|
4007
4207
|
this.camera.getTransform(),
|
|
4008
4208
|
this.options.theme,
|
|
4009
4209
|
this.layerManager.getVisibleLayerNames(),
|
|
4010
4210
|
this.selectedEntityIndex
|
|
4011
4211
|
);
|
|
4212
|
+
this.lastFrameTime = performance.now() - renderStart;
|
|
4213
|
+
this.lastRenderStats = stats;
|
|
4214
|
+
const now = performance.now();
|
|
4215
|
+
if (now - this.lastDoRenderTime >= 3) {
|
|
4216
|
+
this.frameTimestamps.push(now);
|
|
4217
|
+
}
|
|
4218
|
+
this.lastDoRenderTime = now;
|
|
4219
|
+
while (this.frameTimestamps.length > 0 && this.frameTimestamps[0] < now - 1e3) {
|
|
4220
|
+
this.frameTimestamps.shift();
|
|
4221
|
+
}
|
|
4012
4222
|
if (this.currentTool === "measure" && this.measureTool.state.phase !== "idle") {
|
|
4013
4223
|
const ctx = this.renderer.getContext();
|
|
4014
4224
|
renderMeasureOverlay(
|
|
@@ -4020,7 +4230,104 @@ var CadViewer = class {
|
|
|
4020
4230
|
this.options.theme
|
|
4021
4231
|
);
|
|
4022
4232
|
}
|
|
4233
|
+
if (this.debugEnabled) {
|
|
4234
|
+
const ctx = this.renderer.getContext();
|
|
4235
|
+
const debugStats = this.buildDebugStats();
|
|
4236
|
+
this.lastDebugStats = debugStats;
|
|
4237
|
+
renderDebugOverlay(
|
|
4238
|
+
ctx,
|
|
4239
|
+
debugStats,
|
|
4240
|
+
this.options.theme,
|
|
4241
|
+
this.debugOptions,
|
|
4242
|
+
this.renderer.getWidth(),
|
|
4243
|
+
this.renderer.getHeight()
|
|
4244
|
+
);
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
// === Debug Mode ===
|
|
4248
|
+
/**
|
|
4249
|
+
* Enable or disable the debug overlay.
|
|
4250
|
+
* Pass `true` for defaults, `false` to disable, or an object for granular control.
|
|
4251
|
+
*/
|
|
4252
|
+
setDebug(debug) {
|
|
4253
|
+
this.guardDestroyed();
|
|
4254
|
+
if (typeof debug === "boolean") {
|
|
4255
|
+
this.debugEnabled = debug;
|
|
4256
|
+
} else {
|
|
4257
|
+
this.debugEnabled = true;
|
|
4258
|
+
this.debugOptions = resolveDebugOptions(debug);
|
|
4259
|
+
}
|
|
4260
|
+
if (this.debugEnabled) {
|
|
4261
|
+
this.startDebugLoop();
|
|
4262
|
+
} else {
|
|
4263
|
+
this.stopDebugLoop();
|
|
4264
|
+
this.requestRender();
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
startDebugLoop() {
|
|
4268
|
+
if (this.debugRafId) return;
|
|
4269
|
+
const loop = () => {
|
|
4270
|
+
if (!this.debugEnabled || this.destroyed) {
|
|
4271
|
+
this.debugRafId = 0;
|
|
4272
|
+
return;
|
|
4273
|
+
}
|
|
4274
|
+
this.doRender();
|
|
4275
|
+
this.debugRafId = requestAnimationFrame(loop);
|
|
4276
|
+
};
|
|
4277
|
+
this.debugRafId = requestAnimationFrame(loop);
|
|
4278
|
+
}
|
|
4279
|
+
stopDebugLoop() {
|
|
4280
|
+
if (this.debugRafId) {
|
|
4281
|
+
cancelAnimationFrame(this.debugRafId);
|
|
4282
|
+
this.debugRafId = 0;
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
/**
|
|
4286
|
+
* Get the latest debug stats snapshot, or null if debug mode is off.
|
|
4287
|
+
*/
|
|
4288
|
+
getDebugStats() {
|
|
4289
|
+
return this.debugEnabled ? this.lastDebugStats : null;
|
|
4290
|
+
}
|
|
4291
|
+
buildDebugStats() {
|
|
4292
|
+
const vt = this.camera.getTransform();
|
|
4293
|
+
const w = this.renderer.getWidth();
|
|
4294
|
+
const h = this.renderer.getHeight();
|
|
4295
|
+
const bounds = this.computeViewportBounds(vt, w, h);
|
|
4296
|
+
return {
|
|
4297
|
+
fps: this.frameTimestamps.length,
|
|
4298
|
+
frameTime: this.lastFrameTime,
|
|
4299
|
+
renderStats: this.lastRenderStats ?? {
|
|
4300
|
+
entitiesDrawn: 0,
|
|
4301
|
+
entitiesSkipped: 0,
|
|
4302
|
+
drawCalls: 0,
|
|
4303
|
+
byType: {}
|
|
4304
|
+
},
|
|
4305
|
+
entityCount: this.doc?.entities.length ?? 0,
|
|
4306
|
+
layerCount: this.doc?.layers.size ?? 0,
|
|
4307
|
+
visibleLayerCount: this.layerManager.getVisibleLayerNames().size,
|
|
4308
|
+
blockCount: this.doc?.blocks.size ?? 0,
|
|
4309
|
+
parseTime: this.parseTime,
|
|
4310
|
+
spatialIndexBuildTime: this.spatialIndexBuildTime,
|
|
4311
|
+
totalLoadTime: this.parseTime + this.spatialIndexBuildTime,
|
|
4312
|
+
zoom: vt.scale,
|
|
4313
|
+
pixelSize: vt.scale > 0 ? 1 / vt.scale : 0,
|
|
4314
|
+
viewportBounds: bounds,
|
|
4315
|
+
fileName: this.loadedFileName,
|
|
4316
|
+
fileSize: this.loadedFileSize,
|
|
4317
|
+
dxfVersion: this.doc?.header.acadVersion ?? null
|
|
4318
|
+
};
|
|
4319
|
+
}
|
|
4320
|
+
computeViewportBounds(vt, w, h) {
|
|
4321
|
+
const [x1, y1] = screenToWorld(vt, 0, h);
|
|
4322
|
+
const [x2, y2] = screenToWorld(vt, w, 0);
|
|
4323
|
+
return {
|
|
4324
|
+
minX: Math.min(x1, x2),
|
|
4325
|
+
minY: Math.min(y1, y2),
|
|
4326
|
+
maxX: Math.max(x1, x2),
|
|
4327
|
+
maxY: Math.max(y1, y2)
|
|
4328
|
+
};
|
|
4023
4329
|
}
|
|
4330
|
+
// === Internal (called by InputHandler) ===
|
|
4024
4331
|
/** @internal */
|
|
4025
4332
|
handlePan(dx, dy) {
|
|
4026
4333
|
this.camera.pan(dx, dy);
|
|
@@ -4104,6 +4411,6 @@ var CadViewer = class {
|
|
|
4104
4411
|
}
|
|
4105
4412
|
};
|
|
4106
4413
|
|
|
4107
|
-
export { CadViewer, Camera, CanvasRenderer, DxfParseError, EventEmitter, LayerManager, MeasureTool, SpatialIndex, THEMES, aciToDisplayColor, aciToHex, applyTransform, computeEntitiesBounds, computeEntityBBox, drawEntity, findSnaps, fitToView, hitTest, parseDxf, renderMeasureOverlay, resolveEntityColor, screenToWorld, trueColorToHex, worldToScreen, zoomAtPoint };
|
|
4414
|
+
export { CadViewer, Camera, CanvasRenderer, DxfParseError, EventEmitter, LayerManager, MeasureTool, SpatialIndex, THEMES, aciToDisplayColor, aciToHex, applyTransform, computeEntitiesBounds, computeEntityBBox, drawEntity, findSnaps, fitToView, hitTest, parseDxf, renderDebugOverlay, renderMeasureOverlay, resolveEntityColor, screenToWorld, trueColorToHex, worldToScreen, zoomAtPoint };
|
|
4108
4415
|
//# sourceMappingURL=index.js.map
|
|
4109
4416
|
//# sourceMappingURL=index.js.map
|