@mindexec/cli 0.2.458 → 0.2.460
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/desktop-workspace-state.cjs +120 -0
- package/electron/main.cjs +17 -6
- package/electron/source-smoke.mjs +21 -0
- package/electron/windows-package-smoke.mjs +8 -2
- package/package.json +6 -5
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/scripts/desktop-workspace-state-smoke.mjs +81 -0
- package/server.js +36 -16
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-animated-image-preview.js +270 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +106 -60
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +30 -26
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +94 -124
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +43 -21
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +45 -13
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +117 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +4 -1
- package/wwwroot/_framework/{MindExecution.Core.2ch68iyy8o.dll → MindExecution.Core.oqju650dkd.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.dh617xfv36.dll → MindExecution.Kernel.7zjugdfmfg.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.0sm50hbae9.dll → MindExecution.Plugins.Admin.qln7lkmsnn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.3wq01orrbu.dll → MindExecution.Plugins.Business.rd6flxuebm.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.z8yl28fa2a.dll → MindExecution.Plugins.Concept.0qrgx3epss.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.m7murp5oes.dll → MindExecution.Plugins.Directory.4prauy9d1z.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.yuyrbpf0vh.dll → MindExecution.Plugins.PlanMaster.cobfta1p3l.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.rwxvn00rm2.dll → MindExecution.Plugins.YouTube.99bahbgkkr.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.r9k48iyijb.dll → MindExecution.Shared.sevaa4rgkp.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.742aribkxm.dll → MindExecution.Web.coqh2ccnuk.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/app-icon-1024.png +0 -0
- package/wwwroot/apple-touch-icon.png +0 -0
- package/wwwroot/appsettings.json +81 -81
- package/wwwroot/favicon-32x32.png +0 -0
- package/wwwroot/favicon.ico +0 -0
- package/wwwroot/icon-192.png +0 -0
- package/wwwroot/icon-512.png +0 -0
- package/wwwroot/index.html +70 -46
- package/wwwroot/manifest.webmanifest +4 -4
- package/wwwroot/mindexec-favicon-v3.png +0 -0
- package/wwwroot/service-worker-assets.js +888 -880
- package/wwwroot/service-worker.js +1 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Bounded resident previews for animation-capable image formats.
|
|
2
|
+
(function () {
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
function normalizeAssetUrl(url) {
|
|
6
|
+
if (typeof url !== 'string') return '';
|
|
7
|
+
return url.trim()
|
|
8
|
+
.replace(/^http:\/\/localhost(?=:\d+\/assets\/)/i, 'http://127.0.0.1')
|
|
9
|
+
.replace(/^http:\/\/\[::1\](?=:\d+\/assets\/)/i, 'http://127.0.0.1');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getContentType(model) {
|
|
13
|
+
return String(model?.contentType || model?.ContentType || '').trim().toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getMetadata(model) {
|
|
17
|
+
return model?.metadata || model?.Metadata || {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getMetadataValue(metadata, ...keys) {
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
const direct = metadata?.[key];
|
|
23
|
+
if (direct !== undefined && direct !== null && String(direct).trim()) {
|
|
24
|
+
return String(direct).trim();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const wanted = new Set(keys.map(key => String(key).toLowerCase()));
|
|
29
|
+
for (const [key, value] of Object.entries(metadata || {})) {
|
|
30
|
+
if (wanted.has(String(key).toLowerCase()) && value !== undefined && value !== null && String(value).trim()) {
|
|
31
|
+
return String(value).trim();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function hasExtension(url, extension) {
|
|
39
|
+
const pathname = normalizeAssetUrl(url).split(/[?#]/)[0].toLowerCase();
|
|
40
|
+
return !!pathname && pathname.endsWith(extension);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getImageReferenceCandidates(model) {
|
|
44
|
+
const metadata = getMetadata(model);
|
|
45
|
+
return [
|
|
46
|
+
model?.response,
|
|
47
|
+
model?.Response,
|
|
48
|
+
metadata?.OriginalPath,
|
|
49
|
+
metadata?.OriginalUrl,
|
|
50
|
+
metadata?.originalUrl,
|
|
51
|
+
metadata?.ImageUrl,
|
|
52
|
+
metadata?.imageUrl
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isAnimatedGifImageModel(model) {
|
|
57
|
+
if (!model || getContentType(model) !== 'image') return false;
|
|
58
|
+
const metadata = getMetadata(model);
|
|
59
|
+
const mimeType = getMetadataValue(metadata, 'fileMime', 'FileMime', 'mimeType', 'MimeType').toLowerCase();
|
|
60
|
+
return mimeType === 'image/gif' || getImageReferenceCandidates(model).some(url => hasExtension(url, '.gif'));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isWebpImageModel(model) {
|
|
64
|
+
if (!model || getContentType(model) !== 'image') return false;
|
|
65
|
+
const metadata = getMetadata(model);
|
|
66
|
+
const mimeType = getMetadataValue(metadata, 'fileMime', 'FileMime', 'mimeType', 'MimeType').toLowerCase();
|
|
67
|
+
return mimeType === 'image/webp' || getImageReferenceCandidates(model).some(url => hasExtension(url, '.webp'));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isSafeResidentStaticPreviewUrl(url) {
|
|
71
|
+
const normalized = normalizeAssetUrl(url).toLowerCase();
|
|
72
|
+
return normalized.includes('/assets/thumbs/') &&
|
|
73
|
+
!hasExtension(normalized, '.gif') &&
|
|
74
|
+
!hasExtension(normalized, '.webp');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getCanonicalAssetKey(url) {
|
|
78
|
+
const normalized = normalizeAssetUrl(url);
|
|
79
|
+
if (!normalized) return '';
|
|
80
|
+
const withoutQuery = normalized.split(/[?#]/)[0];
|
|
81
|
+
const lower = withoutQuery.toLowerCase();
|
|
82
|
+
for (const marker of ['/assets/thumbs/', '/assets/']) {
|
|
83
|
+
if (!lower.includes(marker)) continue;
|
|
84
|
+
const assetName = withoutQuery.slice(lower.lastIndexOf(marker) + marker.length).split('/').pop() || '';
|
|
85
|
+
const dotIndex = assetName.lastIndexOf('.');
|
|
86
|
+
return (dotIndex > 0 ? assetName.slice(0, dotIndex) : assetName).toLowerCase();
|
|
87
|
+
}
|
|
88
|
+
return withoutQuery.toLowerCase();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function areAssetUrlsEquivalent(leftUrl, rightUrl) {
|
|
92
|
+
const leftKey = getCanonicalAssetKey(leftUrl);
|
|
93
|
+
const rightKey = getCanonicalAssetKey(rightUrl);
|
|
94
|
+
return leftKey && rightKey
|
|
95
|
+
? leftKey === rightKey
|
|
96
|
+
: normalizeAssetUrl(leftUrl) === normalizeAssetUrl(rightUrl);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getLocalWebpAssetFilename(...urls) {
|
|
100
|
+
for (const candidate of urls) {
|
|
101
|
+
const normalized = normalizeAssetUrl(candidate);
|
|
102
|
+
if (!normalized || !hasExtension(normalized, '.webp')) continue;
|
|
103
|
+
|
|
104
|
+
let pathname = normalized.split(/[?#]/)[0];
|
|
105
|
+
try {
|
|
106
|
+
pathname = new URL(normalized, window.location?.origin || 'http://127.0.0.1').pathname;
|
|
107
|
+
} catch { }
|
|
108
|
+
|
|
109
|
+
const normalizedPath = pathname.replace(/\\/g, '/');
|
|
110
|
+
if (!/(^|\/)assets\//i.test(normalizedPath)) continue;
|
|
111
|
+
|
|
112
|
+
const rawFilename = normalizedPath.split('/').pop() || '';
|
|
113
|
+
let filename = rawFilename;
|
|
114
|
+
try { filename = decodeURIComponent(rawFilename); } catch { }
|
|
115
|
+
if (/^[^/\\]+\.webp$/i.test(filename)) return filename;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getBridgeOrigin() {
|
|
122
|
+
const configuredOrigin = String(window.MindExecLocalBridge?.activeBridgeUrl || '').trim();
|
|
123
|
+
return (configuredOrigin || window.location?.origin || 'http://127.0.0.1:5147').replace(/\/$/, '');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function getBridgeAuthHeaders(bridgeOrigin) {
|
|
127
|
+
if (window.__mindExecutionBridgeAuthPromise) {
|
|
128
|
+
try { return await window.__mindExecutionBridgeAuthPromise; } catch { }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const authPromise = (async () => {
|
|
132
|
+
const nonce = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
133
|
+
const response = await fetch(`${bridgeOrigin}/api/status?cb=${encodeURIComponent(nonce)}`, {
|
|
134
|
+
cache: 'no-store',
|
|
135
|
+
targetAddressSpace: 'loopback'
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) return {};
|
|
138
|
+
const status = await response.json();
|
|
139
|
+
const token = String(status?.bridgeToken || '').trim();
|
|
140
|
+
const header = String(status?.bridgeTokenHeader || 'X-Bridge-Token').trim();
|
|
141
|
+
return token && header ? { [header]: token } : {};
|
|
142
|
+
})();
|
|
143
|
+
window.__mindExecutionBridgeAuthPromise = authPromise;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
return await authPromise;
|
|
147
|
+
} catch {
|
|
148
|
+
if (window.__mindExecutionBridgeAuthPromise === authPromise) {
|
|
149
|
+
window.__mindExecutionBridgeAuthPromise = null;
|
|
150
|
+
}
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function resolveLocalWebpResidentPreview(item, assetUrls) {
|
|
156
|
+
const sourceUrl = normalizeAssetUrl(
|
|
157
|
+
item?.originalUrl ||
|
|
158
|
+
assetUrls?.fullResUrl ||
|
|
159
|
+
assetUrls?.originalUrl ||
|
|
160
|
+
assetUrls?.originalPath ||
|
|
161
|
+
item?.previewUrl || ''
|
|
162
|
+
);
|
|
163
|
+
const filename = getLocalWebpAssetFilename(
|
|
164
|
+
sourceUrl,
|
|
165
|
+
assetUrls?.originalPath,
|
|
166
|
+
assetUrls?.originalUrl,
|
|
167
|
+
item?.previewUrl
|
|
168
|
+
);
|
|
169
|
+
if (!filename || typeof fetch !== 'function') {
|
|
170
|
+
return { sourceUrl, previewUrl: '' };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const bridgeOrigin = getBridgeOrigin();
|
|
174
|
+
const headers = await getBridgeAuthHeaders(bridgeOrigin);
|
|
175
|
+
const endpoint = `${bridgeOrigin}/api/assets/generate-thumbnail/${encodeURIComponent(filename)}`;
|
|
176
|
+
const response = await fetch(endpoint, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
headers,
|
|
179
|
+
cache: 'no-store',
|
|
180
|
+
targetAddressSpace: 'loopback'
|
|
181
|
+
});
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
throw new Error(`resident-static-preview-http-${response.status}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const payload = await response.json();
|
|
187
|
+
const previewUrl = normalizeAssetUrl(payload?.thumbnailUrl || '');
|
|
188
|
+
if (!isSafeResidentStaticPreviewUrl(previewUrl)) {
|
|
189
|
+
throw new Error('resident-static-preview-invalid-url');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { sourceUrl, previewUrl };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function getResidentStaticPreviewUrl(renderer, nodeId, model, assetUrls) {
|
|
196
|
+
const normalizedNodeId = String(nodeId || '').trim();
|
|
197
|
+
const previewUrl = normalizeAssetUrl(assetUrls?.previewUrl || '');
|
|
198
|
+
if (!isWebpImageModel(model)) return previewUrl;
|
|
199
|
+
|
|
200
|
+
const sourceUrl = normalizeAssetUrl(
|
|
201
|
+
assetUrls?.fullResUrl || assetUrls?.originalUrl || assetUrls?.originalPath || previewUrl
|
|
202
|
+
);
|
|
203
|
+
const record = normalizedNodeId ? renderer?._residentStaticPreviewUrls?.get(normalizedNodeId) : null;
|
|
204
|
+
if (record?.sourceUrl === sourceUrl && isSafeResidentStaticPreviewUrl(record.previewUrl)) {
|
|
205
|
+
return normalizeAssetUrl(record.previewUrl);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (normalizedNodeId && record) renderer._residentStaticPreviewUrls.delete(normalizedNodeId);
|
|
209
|
+
const existingThumbnailUrl = normalizeAssetUrl(assetUrls?.thumbnailUrl || '');
|
|
210
|
+
if (normalizedNodeId && sourceUrl && isSafeResidentStaticPreviewUrl(existingThumbnailUrl)) {
|
|
211
|
+
renderer._residentStaticPreviewUrls.set(normalizedNodeId, {
|
|
212
|
+
sourceUrl,
|
|
213
|
+
previewUrl: existingThumbnailUrl
|
|
214
|
+
});
|
|
215
|
+
return existingThumbnailUrl;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function resolveSafeResidentPreviewUrl(renderer, item, assetUrls, getCurrentAssetUrls, onReady) {
|
|
222
|
+
if (!isWebpImageModel(item?.model)) {
|
|
223
|
+
return normalizeAssetUrl(item?.previewUrl || assetUrls?.previewUrl || '');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const nodeId = String(item?.nodeId || '').trim();
|
|
227
|
+
const existingPreviewUrl = getResidentStaticPreviewUrl(renderer, nodeId, item.model, {
|
|
228
|
+
...assetUrls,
|
|
229
|
+
thumbnailUrl: item?.thumbnailUrl || assetUrls?.thumbnailUrl || ''
|
|
230
|
+
});
|
|
231
|
+
if (existingPreviewUrl) return existingPreviewUrl;
|
|
232
|
+
|
|
233
|
+
const resolved = await resolveLocalWebpResidentPreview(item, assetUrls);
|
|
234
|
+
const sourceUrl = normalizeAssetUrl(resolved?.sourceUrl || '');
|
|
235
|
+
const previewUrl = normalizeAssetUrl(resolved?.previewUrl || '');
|
|
236
|
+
if (!isSafeResidentStaticPreviewUrl(previewUrl)) return '';
|
|
237
|
+
|
|
238
|
+
if (
|
|
239
|
+
renderer?._disposed === true ||
|
|
240
|
+
item?.previewEpoch !== renderer?._residentStaticPreviewEpoch ||
|
|
241
|
+
renderer?.isInLODMode !== true
|
|
242
|
+
) {
|
|
243
|
+
return '';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const currentEntry = renderer?._module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
247
|
+
const currentAssetUrls = getCurrentAssetUrls?.(currentEntry?.model) || {};
|
|
248
|
+
const currentSourceUrl = normalizeAssetUrl(
|
|
249
|
+
currentAssetUrls?.fullResUrl ||
|
|
250
|
+
currentAssetUrls?.originalUrl ||
|
|
251
|
+
currentAssetUrls?.originalPath ||
|
|
252
|
+
currentAssetUrls?.previewUrl || ''
|
|
253
|
+
);
|
|
254
|
+
if (!currentEntry?.model || currentSourceUrl !== sourceUrl) return '';
|
|
255
|
+
|
|
256
|
+
renderer._residentStaticPreviewUrls.set(nodeId, { sourceUrl, previewUrl });
|
|
257
|
+
onReady?.({ nodeId, sourceKind: 'webp', previewUrl });
|
|
258
|
+
return previewUrl;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
window.MindMapAnimatedImagePreview = Object.freeze({
|
|
262
|
+
normalizeAssetUrl,
|
|
263
|
+
isAnimatedGifImageModel,
|
|
264
|
+
isWebpImageModel,
|
|
265
|
+
isSafeResidentStaticPreviewUrl,
|
|
266
|
+
areAssetUrlsEquivalent,
|
|
267
|
+
getResidentStaticPreviewUrl,
|
|
268
|
+
resolveSafeResidentPreviewUrl
|
|
269
|
+
});
|
|
270
|
+
})();
|
|
@@ -85,6 +85,8 @@
|
|
|
85
85
|
const PASSIVE_OVERLAY_IDLE_DELAY_MS = 500;
|
|
86
86
|
const PASSIVE_OVERLAY_PAN_IDLE_DELAY_MS = 500;
|
|
87
87
|
const CURSOR_DOM_BLINK_DURATION_MS = 1000;
|
|
88
|
+
const CURSOR_WORLD_SIZE = 20;
|
|
89
|
+
const CURSOR_WORLD_THICKNESS = 4;
|
|
88
90
|
const RENDER_DEBUG_METRICS_CACHE_MS = 250;
|
|
89
91
|
const ANIMATION_IDLE_LOW_FPS_DELAY_MS = 500;
|
|
90
92
|
const WHEEL_ZOOM_BURST_QUIET_FRAME_LIMIT = 12;
|
|
@@ -108,13 +110,13 @@
|
|
|
108
110
|
const LOCAL_SNAP_GRID_DIAMETER_PX = LOCAL_SNAP_GRID_RADIUS_PX * 2;
|
|
109
111
|
const LOCAL_SNAP_GRID_FADE_PX = 100;
|
|
110
112
|
const LOCAL_SNAP_GRID_SOLID_RADIUS_PX = LOCAL_SNAP_GRID_RADIUS_PX - LOCAL_SNAP_GRID_FADE_PX;
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
+
const LOCAL_SNAP_GRID_RASTER_MIN_STEP_PX = 0.5;
|
|
114
|
+
const LOCAL_SNAP_GRID_RASTER_MAX_PERIOD_PX = 2048;
|
|
113
115
|
const LOCAL_SNAP_GRID_OPACITY_BUCKET = 0.04;
|
|
114
|
-
const LOCAL_SNAP_GRID_DEFAULT_STEP_PX =
|
|
115
|
-
const LOCAL_SNAP_GRID_DEFAULT_MAJOR_STEP_PX =
|
|
116
|
-
const LOCAL_SNAP_GRID_DEFAULT_OPACITY = 0.
|
|
117
|
-
const LOCAL_SNAP_GRID_TILE_OVERSCAN_PX =
|
|
116
|
+
const LOCAL_SNAP_GRID_DEFAULT_STEP_PX = 10;
|
|
117
|
+
const LOCAL_SNAP_GRID_DEFAULT_MAJOR_STEP_PX = 100;
|
|
118
|
+
const LOCAL_SNAP_GRID_DEFAULT_OPACITY = 0.58;
|
|
119
|
+
const LOCAL_SNAP_GRID_TILE_OVERSCAN_PX = 560;
|
|
118
120
|
const LOCAL_SNAP_GRID_COMPOSITOR_SCALE_MIN = 0.8;
|
|
119
121
|
const LOCAL_SNAP_GRID_COMPOSITOR_SCALE_MAX = 1.5;
|
|
120
122
|
const CAMERA_STATIONARY_INTERACTION_FRAME_DELAY_MS = 48;
|
|
@@ -289,11 +291,11 @@
|
|
|
289
291
|
position: absolute;
|
|
290
292
|
left: 0;
|
|
291
293
|
top: 0;
|
|
292
|
-
width:
|
|
293
|
-
height:
|
|
294
|
+
width: ${CURSOR_WORLD_SIZE}px;
|
|
295
|
+
height: ${CURSOR_WORLD_SIZE}px;
|
|
294
296
|
box-sizing: border-box;
|
|
295
|
-
border-top:
|
|
296
|
-
border-left:
|
|
297
|
+
border-top: ${CURSOR_WORLD_THICKNESS}px solid #000;
|
|
298
|
+
border-left: ${CURSOR_WORLD_THICKNESS}px solid #000;
|
|
297
299
|
pointer-events: none;
|
|
298
300
|
z-index: 2147483000;
|
|
299
301
|
animation: mindMapCursorDomBlink ${CURSOR_DOM_BLINK_DURATION_MS}ms steps(1, end) infinite;
|
|
@@ -347,8 +349,11 @@
|
|
|
347
349
|
const ndcY = ((cursor.y - camera.position.y) * 2) / viewHeight;
|
|
348
350
|
const x = ((ndcX + 1) / 2) * width;
|
|
349
351
|
const y = ((1 - ndcY) / 2) * height;
|
|
352
|
+
const pxPerWorld = height / Math.max(1, viewHeight);
|
|
353
|
+
const cursorSizePx = Math.max(0.5, CURSOR_WORLD_SIZE * pxPerWorld);
|
|
354
|
+
const cursorThicknessPx = Math.max(0.5, CURSOR_WORLD_THICKNESS * pxPerWorld);
|
|
350
355
|
const visible = ndcX >= -1.1 && ndcX <= 1.1 && ndcY >= -1.1 && ndcY <= 1.1;
|
|
351
|
-
const positionKey = `${visible ? 1 : 0}|${Math.round(x)}|${Math.round(y)}|${width}|${height}`;
|
|
356
|
+
const positionKey = `${visible ? 1 : 0}|${Math.round(x)}|${Math.round(y)}|${cursorSizePx.toFixed(2)}|${cursorThicknessPx.toFixed(2)}|${width}|${height}`;
|
|
352
357
|
|
|
353
358
|
if (positionKey === module._lastCursorDomPositionKey) {
|
|
354
359
|
return false;
|
|
@@ -360,6 +365,10 @@
|
|
|
360
365
|
element.style.display = visible ? 'block' : 'none';
|
|
361
366
|
}
|
|
362
367
|
if (visible) {
|
|
368
|
+
element.style.width = `${cursorSizePx.toFixed(2)}px`;
|
|
369
|
+
element.style.height = `${cursorSizePx.toFixed(2)}px`;
|
|
370
|
+
element.style.borderTopWidth = `${cursorThicknessPx.toFixed(2)}px`;
|
|
371
|
+
element.style.borderLeftWidth = `${cursorThicknessPx.toFixed(2)}px`;
|
|
363
372
|
element.style.transform = `translate3d(${x.toFixed(2)}px, ${y.toFixed(2)}px, 0)`;
|
|
364
373
|
}
|
|
365
374
|
return true;
|
|
@@ -3669,23 +3678,8 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3669
3678
|
_resolveLocalSnapGridWorldStep(pxPerWorld) {
|
|
3670
3679
|
const safePxPerWorld = Math.max(Number.EPSILON, Number(pxPerWorld) || Number.EPSILON);
|
|
3671
3680
|
const baseWorldStep = Math.max(Number.EPSILON, Number(this.GRID_SIZE || 10));
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
Number(this._lastLocalSnapGridWorldStep || baseWorldStep)
|
|
3675
|
-
);
|
|
3676
|
-
let smallStepPx = worldStep * safePxPerWorld;
|
|
3677
|
-
let guard = 0;
|
|
3678
|
-
|
|
3679
|
-
while (smallStepPx < LOCAL_SNAP_GRID_MIN_STEP_PX && guard < 24) {
|
|
3680
|
-
worldStep *= 2;
|
|
3681
|
-
smallStepPx *= 2;
|
|
3682
|
-
guard += 1;
|
|
3683
|
-
}
|
|
3684
|
-
while (smallStepPx > LOCAL_SNAP_GRID_MAX_STEP_PX && guard < 48) {
|
|
3685
|
-
worldStep /= 2;
|
|
3686
|
-
smallStepPx /= 2;
|
|
3687
|
-
guard += 1;
|
|
3688
|
-
}
|
|
3681
|
+
const worldStep = baseWorldStep;
|
|
3682
|
+
const smallStepPx = worldStep * safePxPerWorld;
|
|
3689
3683
|
|
|
3690
3684
|
return {
|
|
3691
3685
|
worldStep,
|
|
@@ -3709,37 +3703,43 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3709
3703
|
return false;
|
|
3710
3704
|
}
|
|
3711
3705
|
|
|
3712
|
-
const smallStep = Math.max(
|
|
3706
|
+
const smallStep = Math.max(LOCAL_SNAP_GRID_RASTER_MIN_STEP_PX, Number(smallStepPx) || LOCAL_SNAP_GRID_DEFAULT_STEP_PX);
|
|
3713
3707
|
const majorStep = Math.max(
|
|
3714
3708
|
smallStep,
|
|
3715
3709
|
Math.min(
|
|
3716
|
-
|
|
3710
|
+
LOCAL_SNAP_GRID_RASTER_MAX_PERIOD_PX,
|
|
3717
3711
|
Number(majorStepPx) || LOCAL_SNAP_GRID_DEFAULT_MAJOR_STEP_PX
|
|
3718
3712
|
)
|
|
3719
3713
|
);
|
|
3720
|
-
const tileSize = Math.max(1,
|
|
3721
|
-
|
|
3722
|
-
|
|
3714
|
+
const tileSize = Math.max(1, majorStep);
|
|
3715
|
+
const viewportDpr = Math.max(1, Math.min(3, Number(this._lastViewportDpr || window.devicePixelRatio || 1)));
|
|
3716
|
+
const bitmapSize = Math.max(1, Math.ceil(tileSize * viewportDpr));
|
|
3717
|
+
if (canvas.width !== bitmapSize) {
|
|
3718
|
+
canvas.width = bitmapSize;
|
|
3723
3719
|
}
|
|
3724
|
-
if (canvas.height !==
|
|
3725
|
-
canvas.height =
|
|
3720
|
+
if (canvas.height !== bitmapSize) {
|
|
3721
|
+
canvas.height = bitmapSize;
|
|
3726
3722
|
}
|
|
3723
|
+
const rasterScale = bitmapSize / tileSize;
|
|
3724
|
+
ctx.setTransform(rasterScale, 0, 0, rasterScale, 0, 0);
|
|
3727
3725
|
ctx.clearRect(0, 0, tileSize, tileSize);
|
|
3728
3726
|
|
|
3729
3727
|
if (styleKind === 'dot') {
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
for (let
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3728
|
+
if (smallStep >= 2.25) {
|
|
3729
|
+
ctx.fillStyle = 'rgba(58, 69, 88, 0.68)';
|
|
3730
|
+
const dotRadius = 1.2;
|
|
3731
|
+
for (let y = 0; y < tileSize; y += smallStep) {
|
|
3732
|
+
for (let x = 0; x < tileSize; x += smallStep) {
|
|
3733
|
+
ctx.beginPath();
|
|
3734
|
+
ctx.arc(x, y, dotRadius, 0, Math.PI * 2);
|
|
3735
|
+
ctx.fill();
|
|
3736
|
+
}
|
|
3737
3737
|
}
|
|
3738
3738
|
}
|
|
3739
3739
|
|
|
3740
|
-
ctx.fillStyle = 'rgba(15, 23, 42, 0.
|
|
3740
|
+
ctx.fillStyle = 'rgba(15, 23, 42, 0.82)';
|
|
3741
3741
|
ctx.beginPath();
|
|
3742
|
-
ctx.arc(0, 0, 1.
|
|
3742
|
+
ctx.arc(0, 0, 1.9, 0, Math.PI * 2);
|
|
3743
3743
|
ctx.fill();
|
|
3744
3744
|
} else {
|
|
3745
3745
|
const drawLines = (step, color, width) => {
|
|
@@ -3779,17 +3779,17 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3779
3779
|
|
|
3780
3780
|
const safeStyleKind = styleKind === 'dot' ? 'dot' : 'line';
|
|
3781
3781
|
const safeSmallStep = Math.max(
|
|
3782
|
-
|
|
3783
|
-
|
|
3782
|
+
LOCAL_SNAP_GRID_RASTER_MIN_STEP_PX,
|
|
3783
|
+
Number(smallStepPx) || LOCAL_SNAP_GRID_DEFAULT_STEP_PX
|
|
3784
3784
|
);
|
|
3785
3785
|
const safeMajorStep = Math.max(
|
|
3786
3786
|
safeSmallStep,
|
|
3787
3787
|
Math.min(
|
|
3788
|
-
|
|
3788
|
+
LOCAL_SNAP_GRID_RASTER_MAX_PERIOD_PX,
|
|
3789
3789
|
Number(majorStepPx) || LOCAL_SNAP_GRID_DEFAULT_MAJOR_STEP_PX
|
|
3790
3790
|
)
|
|
3791
3791
|
);
|
|
3792
|
-
const safeOpacity = Math.max(0.
|
|
3792
|
+
const safeOpacity = Math.max(0.28, Math.min(0.68, Number(opacity) || LOCAL_SNAP_GRID_DEFAULT_OPACITY));
|
|
3793
3793
|
const localGridKey = [
|
|
3794
3794
|
keyPrefix,
|
|
3795
3795
|
safeStyleKind,
|
|
@@ -3797,13 +3797,21 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3797
3797
|
Math.round(safeMajorStep * 100),
|
|
3798
3798
|
Math.round(safeOpacity * 100)
|
|
3799
3799
|
].join('|');
|
|
3800
|
-
const
|
|
3800
|
+
const smallStepValue = safeSmallStep.toFixed(3);
|
|
3801
|
+
const majorStepValue = safeMajorStep.toFixed(3);
|
|
3802
|
+
const showMinorDots = safeSmallStep >= 2.25;
|
|
3803
|
+
const backgroundSizeValue = safeStyleKind === 'dot'
|
|
3804
|
+
? (showMinorDots
|
|
3805
|
+
? `${majorStepValue}px ${majorStepValue}px, ${smallStepValue}px ${smallStepValue}px`
|
|
3806
|
+
: `${majorStepValue}px ${majorStepValue}px`)
|
|
3807
|
+
: `${majorStepValue}px ${majorStepValue}px`;
|
|
3808
|
+
const backgroundSizeKey = backgroundSizeValue;
|
|
3801
3809
|
|
|
3802
3810
|
if (localGridKey === this._lastLocalSnapGridKey) {
|
|
3803
3811
|
this._localSnapGridRasterPeriodPx = safeMajorStep;
|
|
3804
3812
|
if (backgroundSizeKey !== this._lastLocalSnapGridBackgroundSizeKey) {
|
|
3805
3813
|
this._lastLocalSnapGridBackgroundSizeKey = backgroundSizeKey;
|
|
3806
|
-
layer.style.backgroundSize =
|
|
3814
|
+
layer.style.backgroundSize = backgroundSizeValue;
|
|
3807
3815
|
this._lastLocalSnapGridTransformKey = '';
|
|
3808
3816
|
}
|
|
3809
3817
|
return false;
|
|
@@ -3811,6 +3819,20 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3811
3819
|
|
|
3812
3820
|
const opacityValue = safeOpacity.toFixed(3);
|
|
3813
3821
|
this._lastLocalSnapGridOpacity = opacityValue;
|
|
3822
|
+
if (safeStyleKind === 'dot') {
|
|
3823
|
+
const majorDot = 'radial-gradient(circle at 0 0, rgba(15, 23, 42, 0.82) 0 1.9px, transparent 2px)';
|
|
3824
|
+
const minorDot = 'radial-gradient(circle at 0 0, rgba(58, 69, 88, 0.68) 0 1.2px, transparent 1.3px)';
|
|
3825
|
+
const backgroundImage = showMinorDots ? `${majorDot}, ${minorDot}` : majorDot;
|
|
3826
|
+
this._lastLocalSnapGridKey = localGridKey;
|
|
3827
|
+
this._lastLocalSnapGridPatternPeriodPx = safeMajorStep;
|
|
3828
|
+
this._localSnapGridRasterPeriodPx = safeMajorStep;
|
|
3829
|
+
this._lastLocalSnapGridTransformKey = '';
|
|
3830
|
+
if (layer.style.backgroundImage !== backgroundImage) layer.style.backgroundImage = backgroundImage;
|
|
3831
|
+
this._lastLocalSnapGridBackgroundSizeKey = backgroundSizeKey;
|
|
3832
|
+
if (layer.style.backgroundSize !== backgroundSizeValue) layer.style.backgroundSize = backgroundSizeValue;
|
|
3833
|
+
if (layer.style.opacity !== opacityValue) layer.style.opacity = opacityValue;
|
|
3834
|
+
return true;
|
|
3835
|
+
}
|
|
3814
3836
|
const tileCanvas = this._localSnapGridTileCanvas || document.createElement('canvas');
|
|
3815
3837
|
this._localSnapGridTileCanvas = tileCanvas;
|
|
3816
3838
|
const tileSize = this._drawLocalSnapGridTile(
|
|
@@ -3828,7 +3850,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3828
3850
|
this._lastLocalSnapGridTransformKey = '';
|
|
3829
3851
|
layer.style.backgroundImage = `url("${tileCanvas.toDataURL('image/png')}")`;
|
|
3830
3852
|
this._lastLocalSnapGridBackgroundSizeKey = backgroundSizeKey;
|
|
3831
|
-
layer.style.backgroundSize =
|
|
3853
|
+
layer.style.backgroundSize = backgroundSizeValue;
|
|
3832
3854
|
if (layer.style.opacity !== opacityValue) {
|
|
3833
3855
|
layer.style.opacity = opacityValue;
|
|
3834
3856
|
}
|
|
@@ -3936,7 +3958,9 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3936
3958
|
const top = Number(viewportMetrics.top || 0);
|
|
3937
3959
|
const pointerRevision = Math.max(0, Number(this._localSnapGridPointerRevision || 0));
|
|
3938
3960
|
|
|
3939
|
-
if (this.isZooming === true &&
|
|
3961
|
+
if (this.isZooming === true &&
|
|
3962
|
+
!!this._lastLocalSnapGridKey &&
|
|
3963
|
+
this._getLocalSnapGridStyleKind() !== 'dot') {
|
|
3940
3964
|
this._syncLocalSnapGridSpotlightPosition(width, height, left, top);
|
|
3941
3965
|
this._lastLocalSnapGridPositionRevision = pointerRevision;
|
|
3942
3966
|
this._localSnapGridStyleDeferredForZoom = true;
|
|
@@ -3955,13 +3979,14 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
3955
3979
|
this._lastLocalSnapGridWorldStep = gridProjection.worldStep;
|
|
3956
3980
|
this._lastLocalSnapGridWorldPeriod = gridProjection.worldStep * 10;
|
|
3957
3981
|
const styleKind = this._getLocalSnapGridStyleKind();
|
|
3958
|
-
const rawOpacity = Math.max(0.
|
|
3982
|
+
const rawOpacity = Math.max(0.38, Math.min(0.64, cameraZ <= 1800 ? 0.60 : 0.60 - ((cameraZ - 1800) / 36000)));
|
|
3959
3983
|
const opacity = Math.max(
|
|
3960
|
-
0.
|
|
3961
|
-
Math.min(0.
|
|
3984
|
+
0.38,
|
|
3985
|
+
Math.min(0.64, Math.round(rawOpacity / LOCAL_SNAP_GRID_OPACITY_BUCKET) * LOCAL_SNAP_GRID_OPACITY_BUCKET)
|
|
3962
3986
|
);
|
|
3963
3987
|
const shouldDeferLocalGridStyleForZoom =
|
|
3964
3988
|
this.isZooming === true &&
|
|
3989
|
+
styleKind !== 'dot' &&
|
|
3965
3990
|
!!this._lastLocalSnapGridKey;
|
|
3966
3991
|
|
|
3967
3992
|
if (shouldDeferLocalGridStyleForZoom !== true) {
|
|
@@ -4013,10 +4038,24 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
4013
4038
|
const height = Math.max(1, Number(viewportMetrics.height || 0));
|
|
4014
4039
|
const left = Number(viewportMetrics.left || 0);
|
|
4015
4040
|
const top = Number(viewportMetrics.top || 0);
|
|
4041
|
+
const styleKind = this._getLocalSnapGridStyleKind();
|
|
4042
|
+
if (this.isZooming === true && styleKind === 'dot') {
|
|
4043
|
+
const cameraZ = Math.max(1, Number(this.camera?.position?.z || 1));
|
|
4044
|
+
const vfov = (Number(this.camera?.fov || 45) * Math.PI) / 180;
|
|
4045
|
+
const pxPerWorld = height / Math.max(1, 2 * Math.tan(vfov / 2) * cameraZ);
|
|
4046
|
+
const projection = this._resolveLocalSnapGridWorldStep(pxPerWorld);
|
|
4047
|
+
const rawOpacity = Math.max(0.38, Math.min(0.64,
|
|
4048
|
+
cameraZ <= 1800 ? 0.60 : 0.60 - ((cameraZ - 1800) / 36000)));
|
|
4049
|
+
const opacity = Math.max(0.38, Math.min(0.64,
|
|
4050
|
+
Math.round(rawOpacity / LOCAL_SNAP_GRID_OPACITY_BUCKET) * LOCAL_SNAP_GRID_OPACITY_BUCKET));
|
|
4051
|
+
this._applyLocalSnapGridStyle(
|
|
4052
|
+
layer, styleKind, projection.smallStepPx, projection.majorStepPx, opacity);
|
|
4053
|
+
this._localSnapGridStyleDeferredForZoom = false;
|
|
4054
|
+
}
|
|
4016
4055
|
this._syncLocalSnapGridSpotlightPosition(width, height, left, top);
|
|
4017
4056
|
this._lastLocalSnapGridPositionRevision = pointerRevision;
|
|
4018
4057
|
|
|
4019
|
-
if (this.isZooming === true) {
|
|
4058
|
+
if (this.isZooming === true && styleKind !== 'dot') {
|
|
4020
4059
|
this._localSnapGridStyleDeferredForZoom = true;
|
|
4021
4060
|
}
|
|
4022
4061
|
this._setLocalSnapGridVisible(true, this._lastLocalSnapGridOpacity || null);
|
|
@@ -6196,7 +6235,10 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
6196
6235
|
this.lodRenderer?.hasPendingNearCssWarmup?.(this) === true;
|
|
6197
6236
|
const isResidentMidFarLodFrame = this.useLODRendering &&
|
|
6198
6237
|
this.lodRenderer?.usesResidentMidFarInstances?.(this.camera) === true;
|
|
6199
|
-
|
|
6238
|
+
// The current camera band owns the boundary frame. isInLODMode
|
|
6239
|
+
// still describes the prior frame until updateLOD applies the
|
|
6240
|
+
// resident/full-res handoff.
|
|
6241
|
+
const isFullResMode = isResidentMidFarLodFrame !== true;
|
|
6200
6242
|
|
|
6201
6243
|
// Event-driven viewport sync handles the common case. Keep the
|
|
6202
6244
|
// fallback poll slow, and skip it entirely while resident MID/FAR
|
|
@@ -6232,7 +6274,7 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
6232
6274
|
const isLodModeActive = this.lodRenderer?.isInLODMode === true;
|
|
6233
6275
|
const residentDirty = isResidentMidFarLodFrame &&
|
|
6234
6276
|
this.lodRenderer?.hasResidentDirtyWork?.(this.camera, this) === true;
|
|
6235
|
-
const residentBandChanging =
|
|
6277
|
+
const residentBandChanging = this.useLODRendering === true &&
|
|
6236
6278
|
this.lodRenderer?.willLodBandChange?.(this.camera) === true;
|
|
6237
6279
|
let canDeferResidentDirtyIdleFrame = false;
|
|
6238
6280
|
let canDeferResidentDirtyMotionFrame = false;
|
|
@@ -7332,8 +7374,12 @@ ${summaryLines.map(line => `<div>${escapeNodeFrameDebugHtml(line)}</div>`).join(
|
|
|
7332
7374
|
!hasNonCameraNavigationForcedUpdate &&
|
|
7333
7375
|
!hasMotionBlockingOverlayFocus &&
|
|
7334
7376
|
!this.isWindowResizing;
|
|
7335
|
-
if (isMenuOverlayUiEnabled && window.MindMapMenuManager
|
|
7336
|
-
|
|
7377
|
+
if (isMenuOverlayUiEnabled && window.MindMapMenuManager) {
|
|
7378
|
+
if (shouldDeferFloatingUiDuringMotion === true) {
|
|
7379
|
+
window.MindMapMenuManager.updateForCameraMotion?.();
|
|
7380
|
+
} else {
|
|
7381
|
+
window.MindMapMenuManager.update();
|
|
7382
|
+
}
|
|
7337
7383
|
} else if (!isMenuOverlayUiEnabled && window.MindMapMenuManager?.hideMenu) {
|
|
7338
7384
|
window.MindMapMenuManager.hideMenu();
|
|
7339
7385
|
}
|