senangwebs-tour 1.0.6 → 1.0.7
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/README.md +21 -9
- package/dist/swt-editor.js +145 -174
- package/dist/swt-editor.js.map +1 -1
- package/dist/swt-editor.min.js +1 -1
- package/dist/swt.js +31 -2
- package/dist/swt.js.map +1 -1
- package/dist/swt.min.js +1 -1
- package/package.json +1 -1
- package/src/editor/js/data-transform.js +42 -0
- package/src/editor/js/editor.js +7 -6
- package/src/editor/js/export-manager.js +5 -67
- package/src/editor/js/hotspot-editor.js +36 -10
- package/src/editor/js/preview-controller.js +8 -62
- package/src/editor/js/scene-manager.js +9 -8
- package/src/editor/js/storage-manager.js +4 -2
- package/src/editor/js/ui-controller.js +35 -21
- package/src/index.js +31 -2
package/README.md
CHANGED
|
@@ -280,13 +280,21 @@ new SWT.Tour(aframeSceneElement, tourConfiguration);
|
|
|
280
280
|
|
|
281
281
|
#### Configuration Structure
|
|
282
282
|
|
|
283
|
+
Both the editor and viewer use the same data format. Scenes are stored as an **array**:
|
|
284
|
+
|
|
283
285
|
```javascript
|
|
284
286
|
{
|
|
285
287
|
initialScene: "scene-id", // Required: Starting scene ID
|
|
286
|
-
scenes:
|
|
287
|
-
|
|
288
|
+
scenes: [ // Required: Array of scenes
|
|
289
|
+
{
|
|
290
|
+
id: "scene-id", // Required: Scene identifier
|
|
288
291
|
name: "Scene Name", // Required: Display name
|
|
289
292
|
panorama: "url-or-dataurl", // Required: Image URL or base64
|
|
293
|
+
thumbnail: "url", // Optional: Thumbnail for editor
|
|
294
|
+
startingPosition: { // Optional: Initial camera orientation
|
|
295
|
+
pitch: 0.1, // Vertical angle (radians)
|
|
296
|
+
yaw: 1.5 // Horizontal angle (radians)
|
|
297
|
+
},
|
|
290
298
|
hotspots: [ // Optional: Array of hotspots
|
|
291
299
|
{
|
|
292
300
|
id: "hotspot-1", // Optional: Auto-generated if omitted
|
|
@@ -301,25 +309,29 @@ new SWT.Tour(aframeSceneElement, tourConfiguration);
|
|
|
301
309
|
},
|
|
302
310
|
appearance: { // Optional: Visual customization
|
|
303
311
|
color: "#00ff00", // Default: "#00ff00"
|
|
304
|
-
scale: 1
|
|
305
|
-
icon: "arrow" //
|
|
312
|
+
scale: "1 1 1", // Default: "1 1 1"
|
|
313
|
+
icon: "arrow" // Optional: Icon name or URL
|
|
306
314
|
},
|
|
307
315
|
tooltip: { // Optional: Hover/focus text
|
|
308
|
-
text: "Click
|
|
316
|
+
text: "Click here", // Tooltip title
|
|
317
|
+
description: "Details" // Optional: Extended description
|
|
318
|
+
},
|
|
319
|
+
cameraOrientation: { // Optional: Camera direction when created
|
|
320
|
+
pitch: -0.02, // Vertical angle (radians)
|
|
321
|
+
yaw: 2.06 // Horizontal angle (radians)
|
|
309
322
|
}
|
|
310
323
|
}
|
|
311
324
|
]
|
|
312
325
|
}
|
|
313
|
-
|
|
326
|
+
]
|
|
314
327
|
}
|
|
315
328
|
```
|
|
316
329
|
|
|
317
330
|
**Important Notes:**
|
|
318
331
|
|
|
319
|
-
- `scenes` is an **
|
|
332
|
+
- `scenes` is an **array** (not an object)
|
|
333
|
+
- The library also accepts `scenes` as an object keyed by ID for backward compatibility
|
|
320
334
|
- Hotspot `position` is in 3D space (typically on 10-unit sphere surface)
|
|
321
|
-
- Editor stores `imageUrl`, library expects `panorama` (export handles conversion)
|
|
322
|
-
- Images can be URLs or Data URLs (base64) for offline tours
|
|
323
335
|
|
|
324
336
|
---
|
|
325
337
|
|
package/dist/swt-editor.js
CHANGED
|
@@ -300,8 +300,10 @@
|
|
|
300
300
|
return false;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
// imageUrl is required for scenes to be valid
|
|
304
|
-
|
|
303
|
+
// panorama or imageUrl is required for scenes to be valid (support both formats)
|
|
304
|
+
const hasImage = (scene.panorama && typeof scene.panorama === "string") ||
|
|
305
|
+
(scene.imageUrl && typeof scene.imageUrl === "string");
|
|
306
|
+
if (!hasImage) {
|
|
305
307
|
return false;
|
|
306
308
|
}
|
|
307
309
|
|
|
@@ -426,7 +428,7 @@
|
|
|
426
428
|
* @param {File|Object} fileOrConfig - Either a File object or a scene config object
|
|
427
429
|
* @param {string} fileOrConfig.id - Scene ID (if config object)
|
|
428
430
|
* @param {string} fileOrConfig.name - Scene name (if config object)
|
|
429
|
-
* @param {string} fileOrConfig.
|
|
431
|
+
* @param {string} fileOrConfig.panorama - Panorama URL (if config object)
|
|
430
432
|
* @param {string} fileOrConfig.thumbnail - Thumbnail URL (if config object)
|
|
431
433
|
* @param {Array} fileOrConfig.hotspots - Hotspots array (if config object)
|
|
432
434
|
*/
|
|
@@ -443,17 +445,17 @@
|
|
|
443
445
|
scene = {
|
|
444
446
|
id: sanitizeId$1(fileOrConfig.name.replace(/\.[^/.]+$/, "")),
|
|
445
447
|
name: fileOrConfig.name.replace(/\.[^/.]+$/, ""),
|
|
446
|
-
|
|
448
|
+
panorama: imageDataUrl,
|
|
447
449
|
thumbnail: thumbnail,
|
|
448
450
|
hotspots: [],
|
|
449
451
|
};
|
|
450
452
|
} else if (typeof fileOrConfig === "object" && fileOrConfig !== null) {
|
|
451
|
-
// Handle config object
|
|
453
|
+
// Handle config object - support both panorama and imageUrl for backward compatibility
|
|
452
454
|
scene = {
|
|
453
455
|
id: fileOrConfig.id || sanitizeId$1(`scene-${Date.now()}`),
|
|
454
456
|
name: fileOrConfig.name || "Untitled Scene",
|
|
455
|
-
|
|
456
|
-
thumbnail: fileOrConfig.thumbnail || fileOrConfig.imageUrl || "",
|
|
457
|
+
panorama: fileOrConfig.panorama || fileOrConfig.imageUrl || "",
|
|
458
|
+
thumbnail: fileOrConfig.thumbnail || fileOrConfig.panorama || fileOrConfig.imageUrl || "",
|
|
457
459
|
hotspots: fileOrConfig.hotspots || [],
|
|
458
460
|
...(fileOrConfig.startingPosition && { startingPosition: fileOrConfig.startingPosition }),
|
|
459
461
|
};
|
|
@@ -523,12 +525,13 @@
|
|
|
523
525
|
if (index >= 0 && index < this.scenes.length) {
|
|
524
526
|
this.scenes[index][property] = value;
|
|
525
527
|
|
|
526
|
-
// If updating ID, update all hotspot target references
|
|
528
|
+
// If updating ID, update all hotspot target references (uses nested action.target)
|
|
527
529
|
if (property === "id") {
|
|
530
|
+
const oldId = this.scenes[index].id;
|
|
528
531
|
this.scenes.forEach((scene) => {
|
|
529
532
|
scene.hotspots.forEach((hotspot) => {
|
|
530
|
-
if (hotspot.
|
|
531
|
-
hotspot.
|
|
533
|
+
if (hotspot.action?.target === oldId) {
|
|
534
|
+
hotspot.action.target = value;
|
|
532
535
|
}
|
|
533
536
|
});
|
|
534
537
|
});
|
|
@@ -649,17 +652,24 @@
|
|
|
649
652
|
return null;
|
|
650
653
|
}
|
|
651
654
|
|
|
655
|
+
// Use unified library format with nested structure
|
|
652
656
|
const hotspot = {
|
|
653
657
|
id: generateId('hotspot'),
|
|
654
|
-
type: 'navigation',
|
|
655
658
|
position: position,
|
|
656
|
-
cameraOrientation: cameraOrientation,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
659
|
+
cameraOrientation: cameraOrientation,
|
|
660
|
+
action: {
|
|
661
|
+
type: 'navigateTo',
|
|
662
|
+
target: targetSceneId
|
|
663
|
+
},
|
|
664
|
+
appearance: {
|
|
665
|
+
color: '#00ff00',
|
|
666
|
+
scale: '1 1 1',
|
|
667
|
+
icon: ''
|
|
668
|
+
},
|
|
669
|
+
tooltip: {
|
|
670
|
+
text: 'New Hotspot',
|
|
671
|
+
description: ''
|
|
672
|
+
}
|
|
663
673
|
};
|
|
664
674
|
|
|
665
675
|
scene.hotspots.push(hotspot);
|
|
@@ -698,6 +708,7 @@
|
|
|
698
708
|
|
|
699
709
|
/**
|
|
700
710
|
* Update hotspot property
|
|
711
|
+
* Supports nested properties like 'appearance.color', 'action.target', 'tooltip.text'
|
|
701
712
|
*/
|
|
702
713
|
updateHotspot(index, property, value) {
|
|
703
714
|
const scene = this.editor.sceneManager.getCurrentScene();
|
|
@@ -705,7 +716,23 @@
|
|
|
705
716
|
return false;
|
|
706
717
|
}
|
|
707
718
|
|
|
708
|
-
scene.hotspots[index]
|
|
719
|
+
const hotspot = scene.hotspots[index];
|
|
720
|
+
|
|
721
|
+
// Handle nested properties (e.g., 'appearance.color')
|
|
722
|
+
if (property.includes('.')) {
|
|
723
|
+
const parts = property.split('.');
|
|
724
|
+
let obj = hotspot;
|
|
725
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
726
|
+
if (!obj[parts[i]]) {
|
|
727
|
+
obj[parts[i]] = {};
|
|
728
|
+
}
|
|
729
|
+
obj = obj[parts[i]];
|
|
730
|
+
}
|
|
731
|
+
obj[parts[parts.length - 1]] = value;
|
|
732
|
+
} else {
|
|
733
|
+
hotspot[property] = value;
|
|
734
|
+
}
|
|
735
|
+
|
|
709
736
|
return true;
|
|
710
737
|
}
|
|
711
738
|
|
|
@@ -772,7 +799,9 @@
|
|
|
772
799
|
const original = scene.hotspots[index];
|
|
773
800
|
const duplicate = deepClone(original);
|
|
774
801
|
duplicate.id = generateId('hotspot');
|
|
775
|
-
duplicate.
|
|
802
|
+
if (duplicate.tooltip) {
|
|
803
|
+
duplicate.tooltip.text = (original.tooltip?.text || 'Hotspot') + ' (Copy)';
|
|
804
|
+
}
|
|
776
805
|
|
|
777
806
|
// Offset position slightly
|
|
778
807
|
duplicate.position = {
|
|
@@ -816,6 +845,49 @@
|
|
|
816
845
|
}
|
|
817
846
|
};
|
|
818
847
|
|
|
848
|
+
/**
|
|
849
|
+
* Data Transform Utilities
|
|
850
|
+
*
|
|
851
|
+
* With the unified format, editor and library use the same structure:
|
|
852
|
+
* - scenes: Array of scene objects with `panorama`
|
|
853
|
+
* - hotspots: nested properties (action, appearance, tooltip)
|
|
854
|
+
*
|
|
855
|
+
* These utilities handle building the tour config for the SWT library.
|
|
856
|
+
*/
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Build a complete tour configuration for the SWT library
|
|
860
|
+
* Since unified format is used, this just wraps the scenes array with config
|
|
861
|
+
* @param {Object} config - Config with initialSceneId, etc.
|
|
862
|
+
* @param {Array} scenes - Array of scenes (already in unified format)
|
|
863
|
+
* @returns {Object} Complete tour config
|
|
864
|
+
*/
|
|
865
|
+
function buildTourConfig(config, scenes) {
|
|
866
|
+
// Determine initial scene
|
|
867
|
+
let initialScene = config.initialSceneId;
|
|
868
|
+
if (!initialScene && scenes && scenes.length > 0) {
|
|
869
|
+
initialScene = scenes[0].id;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
return {
|
|
873
|
+
initialScene: initialScene,
|
|
874
|
+
scenes: scenes || [],
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Build tour config for preview (sets initial scene to current scene)
|
|
880
|
+
* @param {Object} currentScene - The scene to show initially
|
|
881
|
+
* @param {Array} allScenes - All scenes for navigation support
|
|
882
|
+
* @returns {Object} Complete tour config
|
|
883
|
+
*/
|
|
884
|
+
function buildPreviewTourConfig(currentScene, allScenes) {
|
|
885
|
+
return buildTourConfig(
|
|
886
|
+
{ initialSceneId: currentScene.id },
|
|
887
|
+
allScenes
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
819
891
|
// Preview Controller - Manages A-Frame preview integration using SWT library
|
|
820
892
|
|
|
821
893
|
let PreviewController$1 = class PreviewController {
|
|
@@ -866,14 +938,16 @@
|
|
|
866
938
|
|
|
867
939
|
/**
|
|
868
940
|
* Load scene into preview using SWT library
|
|
941
|
+
* Scenes and hotspots now use unified library format directly
|
|
869
942
|
*/
|
|
870
943
|
async loadScene(scene, preserveCameraRotation = true) {
|
|
871
944
|
if (!this.isInitialized || !scene) {
|
|
872
945
|
return;
|
|
873
946
|
}
|
|
874
947
|
|
|
875
|
-
// Validate scene has required data
|
|
876
|
-
|
|
948
|
+
// Validate scene has required data (panorama or imageUrl for backward compatibility)
|
|
949
|
+
const panoramaUrl = scene.panorama || scene.imageUrl;
|
|
950
|
+
if (!panoramaUrl || !scene.id) {
|
|
877
951
|
console.error("Invalid scene data:", scene);
|
|
878
952
|
return;
|
|
879
953
|
}
|
|
@@ -939,65 +1013,10 @@
|
|
|
939
1013
|
// Give A-Frame a moment to start initializing before we proceed
|
|
940
1014
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
941
1015
|
|
|
942
|
-
// Build tour config
|
|
943
|
-
//
|
|
944
|
-
(scene.hotspots || []).map((h) => ({
|
|
945
|
-
id: h.id,
|
|
946
|
-
position: h.position,
|
|
947
|
-
action: {
|
|
948
|
-
type: h.type === "navigation" ? "navigateTo" : h.type,
|
|
949
|
-
target: h.targetSceneId,
|
|
950
|
-
},
|
|
951
|
-
appearance: {
|
|
952
|
-
color: h.color || "#00ff00",
|
|
953
|
-
icon: h.icon || null,
|
|
954
|
-
scale: h.scale || "1 1 1",
|
|
955
|
-
},
|
|
956
|
-
tooltip: {
|
|
957
|
-
text: h.title || "Hotspot",
|
|
958
|
-
},
|
|
959
|
-
}));
|
|
960
|
-
|
|
961
|
-
({
|
|
962
|
-
id: scene.id,
|
|
963
|
-
name: scene.name,
|
|
964
|
-
panorama: scene.imageUrl});
|
|
965
|
-
|
|
966
|
-
// Build scenes object with ALL scenes (for navigation to work)
|
|
967
|
-
const allScenes = {};
|
|
1016
|
+
// Build tour config using shared transform utilities
|
|
1017
|
+
// This includes ALL scenes for navigation support
|
|
968
1018
|
const editorScenes = this.editor.sceneManager.scenes || [];
|
|
969
|
-
editorScenes
|
|
970
|
-
const sceneHotspots = (s.hotspots || []).map((h) => ({
|
|
971
|
-
id: h.id,
|
|
972
|
-
position: h.position,
|
|
973
|
-
action: {
|
|
974
|
-
type: h.type === "navigation" ? "navigateTo" : h.type,
|
|
975
|
-
target: h.targetSceneId,
|
|
976
|
-
},
|
|
977
|
-
appearance: {
|
|
978
|
-
color: h.color || "#00ff00",
|
|
979
|
-
icon: h.icon || null,
|
|
980
|
-
scale: h.scale || "1 1 1",
|
|
981
|
-
},
|
|
982
|
-
tooltip: {
|
|
983
|
-
text: h.title || "Hotspot",
|
|
984
|
-
},
|
|
985
|
-
}));
|
|
986
|
-
|
|
987
|
-
allScenes[s.id] = {
|
|
988
|
-
id: s.id,
|
|
989
|
-
name: s.name,
|
|
990
|
-
panorama: s.imageUrl,
|
|
991
|
-
hotspots: sceneHotspots,
|
|
992
|
-
startingPosition: s.startingPosition || null,
|
|
993
|
-
};
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
const tourConfig = {
|
|
997
|
-
title: scene.name,
|
|
998
|
-
initialScene: scene.id,
|
|
999
|
-
scenes: allScenes,
|
|
1000
|
-
};
|
|
1019
|
+
const tourConfig = buildPreviewTourConfig(scene, editorScenes);
|
|
1001
1020
|
|
|
1002
1021
|
try {
|
|
1003
1022
|
// Create new tour instance
|
|
@@ -4022,9 +4041,9 @@
|
|
|
4022
4041
|
dragHandle.innerHTML =
|
|
4023
4042
|
'<ss-icon icon="arrow-up-down-left-right" thickness="2.2"></ss-icon>';
|
|
4024
4043
|
|
|
4025
|
-
// Thumbnail
|
|
4044
|
+
// Thumbnail - use thumbnail, panorama, or imageUrl (backward compatibility)
|
|
4026
4045
|
const thumbnail = document.createElement("img");
|
|
4027
|
-
thumbnail.src = scene.thumbnail || scene.imageUrl;
|
|
4046
|
+
thumbnail.src = scene.thumbnail || scene.panorama || scene.imageUrl;
|
|
4028
4047
|
thumbnail.alt = scene.name;
|
|
4029
4048
|
|
|
4030
4049
|
// Info
|
|
@@ -4156,18 +4175,25 @@
|
|
|
4156
4175
|
|
|
4157
4176
|
/**
|
|
4158
4177
|
* Create hotspot list item
|
|
4178
|
+
* Uses unified format with nested appearance, action, and tooltip
|
|
4159
4179
|
*/
|
|
4160
4180
|
createHotspotItem(hotspot, index, isActive) {
|
|
4161
4181
|
const item = document.createElement("div");
|
|
4162
4182
|
item.className = "hotspot-item" + (isActive ? " active" : "");
|
|
4163
4183
|
|
|
4184
|
+
// Get values from nested structure
|
|
4185
|
+
const color = hotspot.appearance?.color || "#00ff00";
|
|
4186
|
+
const icon = hotspot.appearance?.icon || "";
|
|
4187
|
+
const title = hotspot.tooltip?.text || "Untitled Hotspot";
|
|
4188
|
+
const targetSceneId = hotspot.action?.target || "";
|
|
4189
|
+
|
|
4164
4190
|
const colorIndicator = document.createElement("div");
|
|
4165
4191
|
colorIndicator.className = "hotspot-color";
|
|
4166
|
-
colorIndicator.style.backgroundColor =
|
|
4192
|
+
colorIndicator.style.backgroundColor = color;
|
|
4167
4193
|
|
|
4168
4194
|
// If hotspot has an icon, show it with the color applied
|
|
4169
|
-
if (
|
|
4170
|
-
colorIndicator.innerHTML = `<ss-icon icon="${
|
|
4195
|
+
if (icon) {
|
|
4196
|
+
colorIndicator.innerHTML = `<ss-icon icon="${icon}" thickness="2.2" style="color: ${color}; width: 20px; height: 20px;"></ss-icon>`;
|
|
4171
4197
|
colorIndicator.style.backgroundColor = "transparent";
|
|
4172
4198
|
colorIndicator.style.display = "flex";
|
|
4173
4199
|
colorIndicator.style.alignItems = "center";
|
|
@@ -4177,24 +4203,24 @@
|
|
|
4177
4203
|
const info = document.createElement("div");
|
|
4178
4204
|
info.className = "hotspot-info";
|
|
4179
4205
|
|
|
4180
|
-
const
|
|
4181
|
-
|
|
4182
|
-
|
|
4206
|
+
const titleEl = document.createElement("div");
|
|
4207
|
+
titleEl.className = "hotspot-title";
|
|
4208
|
+
titleEl.textContent = title;
|
|
4183
4209
|
|
|
4184
4210
|
const target = document.createElement("div");
|
|
4185
4211
|
target.className = "hotspot-target";
|
|
4186
|
-
if (
|
|
4212
|
+
if (targetSceneId) {
|
|
4187
4213
|
const targetScene = this.editor.sceneManager.getSceneById(
|
|
4188
|
-
|
|
4214
|
+
targetSceneId
|
|
4189
4215
|
);
|
|
4190
4216
|
target.textContent = targetScene
|
|
4191
4217
|
? `→ ${targetScene.name}`
|
|
4192
|
-
: `→ ${
|
|
4218
|
+
: `→ ${targetSceneId}`;
|
|
4193
4219
|
} else {
|
|
4194
4220
|
target.textContent = "No target";
|
|
4195
4221
|
}
|
|
4196
4222
|
|
|
4197
|
-
info.appendChild(
|
|
4223
|
+
info.appendChild(titleEl);
|
|
4198
4224
|
info.appendChild(target);
|
|
4199
4225
|
|
|
4200
4226
|
const actions = document.createElement("div");
|
|
@@ -4276,6 +4302,7 @@
|
|
|
4276
4302
|
|
|
4277
4303
|
/**
|
|
4278
4304
|
* Update properties panel for hotspot
|
|
4305
|
+
* Uses unified format with nested appearance, action, and tooltip
|
|
4279
4306
|
*/
|
|
4280
4307
|
updateHotspotProperties(hotspot) {
|
|
4281
4308
|
const hotspotAll = document.getElementById("hotspotAll");
|
|
@@ -4305,21 +4332,26 @@
|
|
|
4305
4332
|
if (hotspotAll) hotspotAll.style.display = "block";
|
|
4306
4333
|
if (hotspotProperties) hotspotProperties.style.display = "block";
|
|
4307
4334
|
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4335
|
+
// Get values from nested structure
|
|
4336
|
+
const title = hotspot.tooltip?.text || "";
|
|
4337
|
+
const description = hotspot.tooltip?.description || "";
|
|
4338
|
+
const targetSceneId = hotspot.action?.target || "";
|
|
4339
|
+
const color = hotspot.appearance?.color || "#00ff00";
|
|
4340
|
+
const icon = hotspot.appearance?.icon || "";
|
|
4341
|
+
|
|
4342
|
+
document.getElementById("hotspotTitle").value = title;
|
|
4343
|
+
document.getElementById("hotspotDescription").value = description;
|
|
4344
|
+
document.getElementById("hotspotTarget").value = targetSceneId;
|
|
4345
|
+
document.getElementById("hotspotColor").value = color;
|
|
4314
4346
|
|
|
4315
4347
|
// Update color text input if it exists
|
|
4316
4348
|
const colorText = document.getElementById("hotspotColorText");
|
|
4317
4349
|
if (colorText) {
|
|
4318
|
-
colorText.value =
|
|
4350
|
+
colorText.value = color;
|
|
4319
4351
|
}
|
|
4320
4352
|
|
|
4321
4353
|
// Update icon grid active button
|
|
4322
|
-
this.setActiveIconButton(
|
|
4354
|
+
this.setActiveIconButton(icon);
|
|
4323
4355
|
|
|
4324
4356
|
// Update position inputs
|
|
4325
4357
|
const pos = hotspot.position || { x: 0, y: 0, z: 0 };
|
|
@@ -4349,7 +4381,8 @@
|
|
|
4349
4381
|
|
|
4350
4382
|
document.getElementById("sceneId").value = scene.id || "";
|
|
4351
4383
|
document.getElementById("sceneName").value = scene.name || "";
|
|
4352
|
-
|
|
4384
|
+
// Support both panorama (unified) and imageUrl (legacy)
|
|
4385
|
+
document.getElementById("sceneImageUrl").value = scene.panorama || scene.imageUrl || "";
|
|
4353
4386
|
|
|
4354
4387
|
// Update starting position display
|
|
4355
4388
|
if (startingPosDisplay) {
|
|
@@ -4586,75 +4619,13 @@
|
|
|
4586
4619
|
/**
|
|
4587
4620
|
* Generate JSON compatible with SWT library
|
|
4588
4621
|
* Follows the tourConfig structure from example-simple.html
|
|
4622
|
+
* Uses shared data-transform utilities for consistent transformation
|
|
4589
4623
|
*/
|
|
4590
4624
|
generateJSON() {
|
|
4591
4625
|
const scenes = this.editor.sceneManager.getAllScenes();
|
|
4592
4626
|
const config = this.editor.config;
|
|
4593
4627
|
|
|
4594
|
-
|
|
4595
|
-
const scenesData = {};
|
|
4596
|
-
scenes.forEach((scene) => {
|
|
4597
|
-
scenesData[scene.id] = {
|
|
4598
|
-
name: scene.name,
|
|
4599
|
-
panorama: scene.imageUrl,
|
|
4600
|
-
hotspots: scene.hotspots.map((hotspot) => {
|
|
4601
|
-
const hotspotData = {
|
|
4602
|
-
position: hotspot.position,
|
|
4603
|
-
};
|
|
4604
|
-
|
|
4605
|
-
// Add action based on hotspot type
|
|
4606
|
-
if (hotspot.type === "navigation" && hotspot.targetSceneId) {
|
|
4607
|
-
hotspotData.action = {
|
|
4608
|
-
type: "navigateTo",
|
|
4609
|
-
target: hotspot.targetSceneId,
|
|
4610
|
-
};
|
|
4611
|
-
} else if (hotspot.type === "info") {
|
|
4612
|
-
hotspotData.action = {
|
|
4613
|
-
type: "showInfo",
|
|
4614
|
-
};
|
|
4615
|
-
}
|
|
4616
|
-
|
|
4617
|
-
// Add appearance
|
|
4618
|
-
hotspotData.appearance = {
|
|
4619
|
-
color: hotspot.color || "#FF6B6B",
|
|
4620
|
-
scale: hotspot.scale || "2 2 2",
|
|
4621
|
-
};
|
|
4622
|
-
|
|
4623
|
-
// Add icon if set
|
|
4624
|
-
if (hotspot.icon) {
|
|
4625
|
-
hotspotData.appearance.icon = hotspot.icon;
|
|
4626
|
-
}
|
|
4627
|
-
|
|
4628
|
-
// Add tooltip if title exists
|
|
4629
|
-
if (hotspot.title) {
|
|
4630
|
-
hotspotData.tooltip = {
|
|
4631
|
-
text: hotspot.title,
|
|
4632
|
-
};
|
|
4633
|
-
}
|
|
4634
|
-
|
|
4635
|
-
return hotspotData;
|
|
4636
|
-
}),
|
|
4637
|
-
};
|
|
4638
|
-
|
|
4639
|
-
// Add starting position if set
|
|
4640
|
-
if (scene.startingPosition) {
|
|
4641
|
-
scenesData[scene.id].startingPosition = scene.startingPosition;
|
|
4642
|
-
}
|
|
4643
|
-
});
|
|
4644
|
-
|
|
4645
|
-
// Determine initial scene
|
|
4646
|
-
let initialScene = config.initialSceneId;
|
|
4647
|
-
if (!initialScene && scenes.length > 0) {
|
|
4648
|
-
initialScene = scenes[0].id;
|
|
4649
|
-
}
|
|
4650
|
-
|
|
4651
|
-
// Build final JSON matching SWT tourConfig format
|
|
4652
|
-
const jsonData = {
|
|
4653
|
-
initialScene: initialScene,
|
|
4654
|
-
scenes: scenesData,
|
|
4655
|
-
};
|
|
4656
|
-
|
|
4657
|
-
return jsonData;
|
|
4628
|
+
return buildTourConfig(config, scenes);
|
|
4658
4629
|
}
|
|
4659
4630
|
|
|
4660
4631
|
/**
|
|
@@ -4665,9 +4636,8 @@
|
|
|
4665
4636
|
const jsonData = this.generateJSON();
|
|
4666
4637
|
|
|
4667
4638
|
// Process all scenes and convert icon names to data URLs
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4639
|
+
// Scenes are an array in unified format
|
|
4640
|
+
for (const scene of jsonData.scenes) {
|
|
4671
4641
|
for (let i = 0; i < scene.hotspots.length; i++) {
|
|
4672
4642
|
const hotspot = scene.hotspots[i];
|
|
4673
4643
|
const icon = hotspot.appearance?.icon;
|
|
@@ -4968,19 +4938,19 @@
|
|
|
4968
4938
|
});
|
|
4969
4939
|
|
|
4970
4940
|
document.getElementById('hotspotTitle')?.addEventListener('input', debounce((e) => {
|
|
4971
|
-
this.updateCurrentHotspot('
|
|
4941
|
+
this.updateCurrentHotspot('tooltip.text', e.target.value);
|
|
4972
4942
|
}, 300));
|
|
4973
4943
|
|
|
4974
4944
|
document.getElementById('hotspotDescription')?.addEventListener('input', debounce((e) => {
|
|
4975
|
-
this.updateCurrentHotspot('description', e.target.value);
|
|
4945
|
+
this.updateCurrentHotspot('tooltip.description', e.target.value);
|
|
4976
4946
|
}, 300));
|
|
4977
4947
|
|
|
4978
4948
|
document.getElementById('hotspotTarget')?.addEventListener('change', (e) => {
|
|
4979
|
-
this.updateCurrentHotspot('
|
|
4949
|
+
this.updateCurrentHotspot('action.target', e.target.value);
|
|
4980
4950
|
});
|
|
4981
4951
|
|
|
4982
4952
|
document.getElementById('hotspotColor')?.addEventListener('input', (e) => {
|
|
4983
|
-
this.updateCurrentHotspot('color', e.target.value);
|
|
4953
|
+
this.updateCurrentHotspot('appearance.color', e.target.value);
|
|
4984
4954
|
});
|
|
4985
4955
|
|
|
4986
4956
|
// Icon grid button clicks
|
|
@@ -4992,7 +4962,7 @@
|
|
|
4992
4962
|
document.querySelectorAll('#hotspotIconGrid .icon-btn').forEach(b => b.classList.remove('active'));
|
|
4993
4963
|
btn.classList.add('active');
|
|
4994
4964
|
// Update hotspot
|
|
4995
|
-
this.updateCurrentHotspot('icon', iconValue);
|
|
4965
|
+
this.updateCurrentHotspot('appearance.icon', iconValue);
|
|
4996
4966
|
}
|
|
4997
4967
|
});
|
|
4998
4968
|
|
|
@@ -5321,7 +5291,8 @@
|
|
|
5321
5291
|
const index = this.sceneManager.currentSceneIndex;
|
|
5322
5292
|
if (index < 0) return;
|
|
5323
5293
|
|
|
5324
|
-
|
|
5294
|
+
// Use panorama for unified format
|
|
5295
|
+
if (this.sceneManager.updateScene(index, 'panorama', imageUrl)) {
|
|
5325
5296
|
const scene = this.sceneManager.getCurrentScene();
|
|
5326
5297
|
if (scene) {
|
|
5327
5298
|
scene.thumbnail = imageUrl;
|