senangwebs-tour 1.0.2 → 1.0.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.
- package/README.md +190 -217
- package/dist/swt-editor.css +759 -730
- package/dist/swt-editor.css.map +1 -1
- package/dist/swt-editor.js +550 -602
- package/dist/swt-editor.js.map +1 -1
- package/dist/swt-editor.min.css +1 -1
- package/dist/swt-editor.min.js +1 -1
- package/dist/swt.js +56531 -867
- package/dist/swt.js.map +1 -1
- package/dist/swt.min.js +12 -1
- package/package.json +6 -3
- package/src/editor/css/main.css +610 -581
- package/src/editor/js/export-manager.js +175 -262
- package/src/editor/js/preview-controller.js +36 -17
- package/src/editor/js/ui-controller.js +377 -362
- package/src/index.js +45 -33
package/README.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# SenangWebs Tour (SWT)
|
|
2
2
|
|
|
3
3
|
A powerful, data-driven 360° virtual tour system built on A-Frame WebVR. Create immersive virtual tours with a visual editor, or integrate the lightweight viewer library into your own projects.
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
[](LICENSE.md)
|
|
6
|
+
[](https://aframe.io/)
|
|
7
|
+
[](https://github.com/bookklik-technologies/senangstart-icons)
|
|
8
|
+
|
|
9
|
+
| viewer | editor |
|
|
10
|
+
| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
|  |  |
|
|
5
12
|
|
|
6
13
|
## Table of Contents
|
|
7
14
|
|
|
@@ -23,6 +30,7 @@ A powerful, data-driven 360° virtual tour system built on A-Frame WebVR. Create
|
|
|
23
30
|
## Features
|
|
24
31
|
|
|
25
32
|
### Core Capabilities
|
|
33
|
+
|
|
26
34
|
- **Visual Editor** - No-code tour builder with click-to-place hotspot interface
|
|
27
35
|
- **Viewer Library** - Lightweight (12KB minified) JavaScript library for embedding tours
|
|
28
36
|
- **Standalone Viewer** - Self-contained HTML viewer with drag-and-drop JSON support
|
|
@@ -31,6 +39,7 @@ A powerful, data-driven 360° virtual tour system built on A-Frame WebVR. Create
|
|
|
31
39
|
- **Multiple Export Formats** - JSON configuration or standalone HTML files
|
|
32
40
|
|
|
33
41
|
### Developer-Friendly
|
|
42
|
+
|
|
34
43
|
- **Two Integration Modes** - Declarative (HTML attributes) or Programmatic (JavaScript API)
|
|
35
44
|
- **Modular Architecture** - Six-controller editor pattern with clear separation of concerns
|
|
36
45
|
- **Event System** - React to scene loads, hotspot clicks, and navigation events
|
|
@@ -41,21 +50,24 @@ A powerful, data-driven 360° virtual tour system built on A-Frame WebVR. Create
|
|
|
41
50
|
|
|
42
51
|
### Using the Visual Editor (No Coding Required)
|
|
43
52
|
|
|
44
|
-
1. **Start Local Server
|
|
53
|
+
1. **Start Local Server**:
|
|
54
|
+
|
|
45
55
|
```bash
|
|
46
56
|
npm install
|
|
47
|
-
npm run
|
|
57
|
+
npm run dev
|
|
48
58
|
```
|
|
49
59
|
|
|
50
60
|
2. **Open Editor**: Navigate to `http://localhost:8080/examples/editor.html`
|
|
51
61
|
|
|
52
62
|
3. **Create Your Tour**:
|
|
63
|
+
|
|
53
64
|
- Click **"Add Scene"** and upload 360° panorama images (JPG/PNG)
|
|
54
65
|
- Click **"Add Hotspot"** then click on the preview to place navigation points
|
|
55
66
|
- Configure hotspot properties: color, scale, tooltip text, target scene
|
|
56
67
|
- See changes instantly in the live A-Frame preview
|
|
57
68
|
|
|
58
69
|
4. **Export Your Tour**:
|
|
70
|
+
|
|
59
71
|
- **JSON Export** → Portable config file for library integration
|
|
60
72
|
- **Viewer Export** → Self-contained HTML file (no dependencies needed)
|
|
61
73
|
|
|
@@ -68,52 +80,55 @@ A powerful, data-driven 360° virtual tour system built on A-Frame WebVR. Create
|
|
|
68
80
|
```html
|
|
69
81
|
<!DOCTYPE html>
|
|
70
82
|
<html>
|
|
71
|
-
<head>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
<head>
|
|
84
|
+
<script src="https://unpkg.com/senangwebs-tour@latest/dist/swt.min.js"></script>
|
|
85
|
+
</head>
|
|
86
|
+
<body>
|
|
87
|
+
<a-scene id="tour-scene">
|
|
88
|
+
<a-camera><a-cursor></a-cursor></a-camera>
|
|
89
|
+
</a-scene>
|
|
90
|
+
|
|
91
|
+
<script>
|
|
92
|
+
const config = {
|
|
93
|
+
initialScene: "room1",
|
|
94
|
+
scenes: {
|
|
95
|
+
room1: {
|
|
96
|
+
name: "Living Room",
|
|
97
|
+
panorama: "path/to/panorama1.jpg",
|
|
98
|
+
hotspots: [
|
|
99
|
+
{
|
|
100
|
+
position: { x: 5, y: 0, z: -5 },
|
|
101
|
+
action: { type: "navigateTo", target: "room2" },
|
|
102
|
+
appearance: { color: "#FF6B6B", scale: 1.5 },
|
|
103
|
+
tooltip: { text: "Go to Kitchen" },
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
room2: {
|
|
108
|
+
name: "Kitchen",
|
|
109
|
+
panorama: "path/to/panorama2.jpg",
|
|
110
|
+
hotspots: [
|
|
111
|
+
{
|
|
112
|
+
position: { x: -5, y: 0, z: 5 },
|
|
113
|
+
action: { type: "navigateTo", target: "room1" },
|
|
114
|
+
appearance: { color: "#4ECDC4", scale: 1.5 },
|
|
115
|
+
tooltip: { text: "Back to Living Room" },
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
93
119
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const scene = document.querySelector('#tour-scene');
|
|
108
|
-
scene.addEventListener('loaded', () => {
|
|
109
|
-
const tour = new SWT.Tour(scene, config);
|
|
110
|
-
tour.addEventListener('scene-loaded', (e) => {
|
|
111
|
-
console.log('Now viewing:', e.detail.sceneName);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const scene = document.querySelector("#tour-scene");
|
|
123
|
+
scene.addEventListener("loaded", () => {
|
|
124
|
+
const tour = new SWT.Tour(scene, config);
|
|
125
|
+
tour.addEventListener("scene-loaded", (e) => {
|
|
126
|
+
console.log("Now viewing:", e.detail.sceneName);
|
|
127
|
+
});
|
|
128
|
+
tour.start();
|
|
112
129
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</script>
|
|
116
|
-
</body>
|
|
130
|
+
</script>
|
|
131
|
+
</body>
|
|
117
132
|
</html>
|
|
118
133
|
```
|
|
119
134
|
|
|
@@ -128,22 +143,26 @@ Build your own tour editor using the `swt-editor.js` bundle. Two initialization
|
|
|
128
143
|
```html
|
|
129
144
|
<!DOCTYPE html>
|
|
130
145
|
<html>
|
|
131
|
-
<head>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
<head>
|
|
147
|
+
<script src="https://unpkg.com/senangwebs-tour@latest/dist/swt.js"></script>
|
|
148
|
+
<script src="https://unpkg.com/senangwebs-tour@latest/dist/swt-editor.js"></script>
|
|
149
|
+
<link
|
|
150
|
+
rel="stylesheet"
|
|
151
|
+
href="https://unpkg.com/senangwebs-tour@latest/dist/swt-editor.css"
|
|
152
|
+
/>
|
|
153
|
+
</head>
|
|
154
|
+
<body>
|
|
155
|
+
<!-- Auto-initializes on page load -->
|
|
156
|
+
<div
|
|
157
|
+
data-swt-editor
|
|
158
|
+
data-swt-auto-init="true"
|
|
159
|
+
data-swt-project-name="My Virtual Tour"
|
|
160
|
+
>
|
|
161
|
+
<div data-swt-scene-list></div>
|
|
162
|
+
<div data-swt-preview-area></div>
|
|
163
|
+
<div data-swt-properties-panel></div>
|
|
164
|
+
</div>
|
|
165
|
+
</body>
|
|
147
166
|
</html>
|
|
148
167
|
```
|
|
149
168
|
|
|
@@ -168,47 +187,50 @@ Build your own tour editor using the `swt-editor.js` bundle. Two initialization
|
|
|
168
187
|
```html
|
|
169
188
|
<!DOCTYPE html>
|
|
170
189
|
<html>
|
|
171
|
-
<head>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<div id="
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
190
|
+
<head>
|
|
191
|
+
<script src="https://unpkg.com/senangwebs-tour@latest/dist/swt.js"></script>
|
|
192
|
+
<script src="https://unpkg.com/senangwebs-tour@latest/dist/swt-editor.js"></script>
|
|
193
|
+
<link
|
|
194
|
+
rel="stylesheet"
|
|
195
|
+
href="https://unpkg.com/senangwebs-tour@latest/dist/swt-editor.css"
|
|
196
|
+
/>
|
|
197
|
+
</head>
|
|
198
|
+
<body>
|
|
199
|
+
<div id="editor-container">
|
|
200
|
+
<div id="scenes"></div>
|
|
201
|
+
<div id="preview"></div>
|
|
202
|
+
<div id="properties"></div>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<script>
|
|
206
|
+
// Create editor instance with custom config
|
|
207
|
+
const editor = new TourEditor({
|
|
208
|
+
projectName: "My Custom Tour",
|
|
209
|
+
autoSave: true,
|
|
210
|
+
autoSaveInterval: 30000,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Initialize with DOM elements
|
|
214
|
+
editor.init({
|
|
215
|
+
sceneListElement: document.getElementById("scenes"),
|
|
216
|
+
previewElement: document.getElementById("preview"),
|
|
217
|
+
propertiesElement: document.getElementById("properties"),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Access editor programmatically
|
|
221
|
+
editor.addEventListener("scene-added", (scene) => {
|
|
222
|
+
console.log("New scene:", scene.name);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Export tour configuration
|
|
226
|
+
const config = editor.exportJSON();
|
|
227
|
+
</script>
|
|
228
|
+
</body>
|
|
208
229
|
</html>
|
|
209
230
|
```
|
|
210
231
|
|
|
211
232
|
**Available Classes** (all attached to `window` after loading `swt-editor.js`):
|
|
233
|
+
|
|
212
234
|
- `TourEditor` - Main coordinator, orchestrates all managers
|
|
213
235
|
- `SceneManagerEditor` - Scene CRUD operations
|
|
214
236
|
- `HotspotEditor` - Hotspot placement and editing
|
|
@@ -218,6 +240,7 @@ Build your own tour editor using the `swt-editor.js` bundle. Two initialization
|
|
|
218
240
|
- `ExportManager` - JSON and HTML export
|
|
219
241
|
|
|
220
242
|
**Examples:**
|
|
243
|
+
|
|
221
244
|
- `examples/editor-declarative.html` - Declarative HTML-only mode
|
|
222
245
|
- `examples/editor.html` - Full-featured programmatic editor
|
|
223
246
|
|
|
@@ -234,57 +257,6 @@ npm run build
|
|
|
234
257
|
|
|
235
258
|
# Development mode (watch for changes)
|
|
236
259
|
npm run dev
|
|
237
|
-
|
|
238
|
-
# Serve locally (required for A-Frame CORS)
|
|
239
|
-
npm run serve
|
|
240
|
-
# Access at http://localhost:8080
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Build Output
|
|
244
|
-
|
|
245
|
-
| File | Size | Format | Purpose |
|
|
246
|
-
|------|------|--------|---------|
|
|
247
|
-
| `dist/swt.js` | 26KB | UMD | Viewer library (development) |
|
|
248
|
-
| `dist/swt.min.js` | 12KB | UMD | Viewer library (production) |
|
|
249
|
-
| `dist/swt-editor.js` | 89KB | IIFE | Editor bundle (development) |
|
|
250
|
-
| `dist/swt-editor.min.js` | 38KB | IIFE | Editor bundle (production) |
|
|
251
|
-
| `dist/swt-editor.css` | 39KB | CSS | Editor styles (development) |
|
|
252
|
-
| `dist/swt-editor.min.css` | 25KB | CSS | Editor styles (production) |
|
|
253
|
-
|
|
254
|
-
All builds include **sourcemaps** for debugging.
|
|
255
|
-
|
|
256
|
-
### Project Structure
|
|
257
|
-
|
|
258
|
-
```
|
|
259
|
-
src/
|
|
260
|
-
├── index.js # Viewer library entry (UMD export)
|
|
261
|
-
├── AssetManager.js # Panorama preloading
|
|
262
|
-
├── SceneManager.js # Sky entity, transitions, fades
|
|
263
|
-
├── HotspotManager.js # Hotspot creation & updates
|
|
264
|
-
├── components/
|
|
265
|
-
│ └── hotspot-listener.js # A-Frame hotspot component
|
|
266
|
-
└── editor/
|
|
267
|
-
├── editor-entry.js # Editor bundle entry (IIFE)
|
|
268
|
-
├── editor-entry.css # CSS bundle entry (@import)
|
|
269
|
-
├── css/
|
|
270
|
-
│ └── main.css # Editor UI styles
|
|
271
|
-
└── js/
|
|
272
|
-
├── editor.js # Main coordinator (TourEditor)
|
|
273
|
-
├── scene-manager.js # Scene CRUD (SceneManagerEditor)
|
|
274
|
-
├── hotspot-editor.js # Hotspot placement (HotspotEditor)
|
|
275
|
-
├── preview-controller.js # A-Frame preview (PreviewController)
|
|
276
|
-
├── ui-controller.js # DOM rendering (UIController)
|
|
277
|
-
├── storage-manager.js # LocalStorage (ProjectStorageManager)
|
|
278
|
-
├── export-manager.js # JSON/HTML export (ExportManager)
|
|
279
|
-
├── utils.js # Helper functions
|
|
280
|
-
└── ui-init.js # DOMContentLoaded initialization
|
|
281
|
-
|
|
282
|
-
examples/
|
|
283
|
-
├── example.html # Full viewer demo
|
|
284
|
-
├── example-simple.html # Minimal viewer demo
|
|
285
|
-
├── editor.html # Full editor demo
|
|
286
|
-
├── editor-declarative.html # Declarative editor demo
|
|
287
|
-
└── viewer.html # Standalone drag-and-drop viewer
|
|
288
260
|
```
|
|
289
261
|
|
|
290
262
|
## API Documentation
|
|
@@ -294,10 +266,11 @@ examples/
|
|
|
294
266
|
#### Constructor
|
|
295
267
|
|
|
296
268
|
```javascript
|
|
297
|
-
new SWT.Tour(aframeSceneElement, tourConfiguration)
|
|
269
|
+
new SWT.Tour(aframeSceneElement, tourConfiguration);
|
|
298
270
|
```
|
|
299
271
|
|
|
300
272
|
**Parameters:**
|
|
273
|
+
|
|
301
274
|
- `aframeSceneElement` (HTMLElement) - A-Frame `<a-scene>` DOM element
|
|
302
275
|
- `tourConfiguration` (Object) - Tour config (see structure below)
|
|
303
276
|
|
|
@@ -342,6 +315,7 @@ new SWT.Tour(aframeSceneElement, tourConfiguration)
|
|
|
342
315
|
```
|
|
343
316
|
|
|
344
317
|
**Important Notes:**
|
|
318
|
+
|
|
345
319
|
- `scenes` is an **object** (keys are scene IDs), not an array
|
|
346
320
|
- Hotspot `position` is in 3D space (typically on 10-unit sphere surface)
|
|
347
321
|
- Editor stores `imageUrl`, library expects `panorama` (export handles conversion)
|
|
@@ -352,11 +326,13 @@ new SWT.Tour(aframeSceneElement, tourConfiguration)
|
|
|
352
326
|
#### Methods
|
|
353
327
|
|
|
354
328
|
##### `tour.start()`
|
|
329
|
+
|
|
355
330
|
Initialize and start the tour. Loads the initial scene and sets up event listeners.
|
|
356
331
|
|
|
357
332
|
**Returns:** `void`
|
|
358
333
|
|
|
359
334
|
**Example:**
|
|
335
|
+
|
|
360
336
|
```javascript
|
|
361
337
|
const tour = new SWT.Tour(sceneElement, config);
|
|
362
338
|
tour.start();
|
|
@@ -365,39 +341,46 @@ tour.start();
|
|
|
365
341
|
---
|
|
366
342
|
|
|
367
343
|
##### `tour.navigateTo(sceneId)`
|
|
344
|
+
|
|
368
345
|
Navigate to a specific scene by ID.
|
|
369
346
|
|
|
370
347
|
**Parameters:**
|
|
348
|
+
|
|
371
349
|
- `sceneId` (String) - Target scene ID (must exist in `scenes` object)
|
|
372
350
|
|
|
373
351
|
**Returns:** `void`
|
|
374
352
|
|
|
375
353
|
**Example:**
|
|
354
|
+
|
|
376
355
|
```javascript
|
|
377
|
-
tour.navigateTo(
|
|
356
|
+
tour.navigateTo("bedroom"); // Loads scene with id "bedroom"
|
|
378
357
|
```
|
|
379
358
|
|
|
380
359
|
---
|
|
381
360
|
|
|
382
361
|
##### `tour.getCurrentSceneId()`
|
|
362
|
+
|
|
383
363
|
Get the ID of the currently active scene.
|
|
384
364
|
|
|
385
365
|
**Returns:** `String` - Current scene ID
|
|
386
366
|
|
|
387
367
|
**Example:**
|
|
368
|
+
|
|
388
369
|
```javascript
|
|
389
370
|
const currentScene = tour.getCurrentSceneId();
|
|
390
|
-
console.log(
|
|
371
|
+
console.log("Viewing:", currentScene); // "living-room"
|
|
391
372
|
```
|
|
392
373
|
|
|
393
374
|
---
|
|
394
375
|
|
|
395
376
|
##### `tour.destroy()`
|
|
377
|
+
|
|
396
378
|
Clean up and remove the tour. Removes all hotspots, event listeners, and resets scene.
|
|
397
379
|
|
|
398
380
|
**Returns:** `void`
|
|
399
381
|
|
|
400
382
|
**Example:**
|
|
383
|
+
|
|
401
384
|
```javascript
|
|
402
385
|
tour.destroy(); // Cleanup before removing from DOM
|
|
403
386
|
```
|
|
@@ -405,18 +388,21 @@ tour.destroy(); // Cleanup before removing from DOM
|
|
|
405
388
|
---
|
|
406
389
|
|
|
407
390
|
##### `tour.addEventListener(eventName, callback)`
|
|
391
|
+
|
|
408
392
|
Listen to tour events. Custom event system (not DOM events).
|
|
409
393
|
|
|
410
394
|
**Parameters:**
|
|
395
|
+
|
|
411
396
|
- `eventName` (String) - Event name (see Events section)
|
|
412
397
|
- `callback` (Function) - Handler function receiving event object
|
|
413
398
|
|
|
414
399
|
**Returns:** `void`
|
|
415
400
|
|
|
416
401
|
**Example:**
|
|
402
|
+
|
|
417
403
|
```javascript
|
|
418
|
-
tour.addEventListener(
|
|
419
|
-
console.log(
|
|
404
|
+
tour.addEventListener("scene-loaded", (event) => {
|
|
405
|
+
console.log("Scene:", event.detail.sceneName);
|
|
420
406
|
});
|
|
421
407
|
```
|
|
422
408
|
|
|
@@ -427,33 +413,39 @@ tour.addEventListener('scene-loaded', (event) => {
|
|
|
427
413
|
All events include a `detail` object with event-specific data.
|
|
428
414
|
|
|
429
415
|
##### `tour-started`
|
|
416
|
+
|
|
430
417
|
Fired when `tour.start()` is called.
|
|
431
418
|
|
|
432
419
|
**Detail:**
|
|
420
|
+
|
|
433
421
|
```javascript
|
|
434
422
|
{
|
|
435
|
-
config: Object // Full tour configuration
|
|
423
|
+
config: Object; // Full tour configuration
|
|
436
424
|
}
|
|
437
425
|
```
|
|
438
426
|
|
|
439
427
|
---
|
|
440
428
|
|
|
441
429
|
##### `scene-loading`
|
|
430
|
+
|
|
442
431
|
Fired before a scene begins loading.
|
|
443
432
|
|
|
444
433
|
**Detail:**
|
|
434
|
+
|
|
445
435
|
```javascript
|
|
446
436
|
{
|
|
447
|
-
sceneId: String // ID of scene being loaded
|
|
437
|
+
sceneId: String; // ID of scene being loaded
|
|
448
438
|
}
|
|
449
439
|
```
|
|
450
440
|
|
|
451
441
|
---
|
|
452
442
|
|
|
453
443
|
##### `scene-loaded`
|
|
444
|
+
|
|
454
445
|
Fired after a scene is fully loaded and rendered.
|
|
455
446
|
|
|
456
447
|
**Detail:**
|
|
448
|
+
|
|
457
449
|
```javascript
|
|
458
450
|
{
|
|
459
451
|
sceneId: String, // ID of loaded scene
|
|
@@ -464,9 +456,11 @@ Fired after a scene is fully loaded and rendered.
|
|
|
464
456
|
---
|
|
465
457
|
|
|
466
458
|
##### `hotspot-activated`
|
|
459
|
+
|
|
467
460
|
Fired when a hotspot is clicked/activated.
|
|
468
461
|
|
|
469
462
|
**Detail:**
|
|
463
|
+
|
|
470
464
|
```javascript
|
|
471
465
|
{
|
|
472
466
|
hotspotId: String, // Hotspot ID
|
|
@@ -480,46 +474,48 @@ Fired when a hotspot is clicked/activated.
|
|
|
480
474
|
#### Usage Example
|
|
481
475
|
|
|
482
476
|
```javascript
|
|
483
|
-
const scene = document.querySelector(
|
|
477
|
+
const scene = document.querySelector("#vr-scene");
|
|
484
478
|
const tour = new SWT.Tour(scene, {
|
|
485
479
|
initialScene: "room1",
|
|
486
480
|
scenes: {
|
|
487
481
|
room1: {
|
|
488
482
|
name: "Living Room",
|
|
489
483
|
panorama: "360-living-room.jpg",
|
|
490
|
-
hotspots: [
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
484
|
+
hotspots: [
|
|
485
|
+
{
|
|
486
|
+
position: { x: 5, y: 0, z: -5 },
|
|
487
|
+
action: { type: "navigateTo", target: "room2" },
|
|
488
|
+
appearance: { color: "#FF6B6B" },
|
|
489
|
+
tooltip: { text: "Kitchen" },
|
|
490
|
+
},
|
|
491
|
+
],
|
|
496
492
|
},
|
|
497
493
|
room2: {
|
|
498
494
|
name: "Kitchen",
|
|
499
495
|
panorama: "360-kitchen.jpg",
|
|
500
|
-
hotspots: []
|
|
501
|
-
}
|
|
502
|
-
}
|
|
496
|
+
hotspots: [],
|
|
497
|
+
},
|
|
498
|
+
},
|
|
503
499
|
});
|
|
504
500
|
|
|
505
501
|
// Listen to events
|
|
506
|
-
tour.addEventListener(
|
|
507
|
-
console.log(
|
|
502
|
+
tour.addEventListener("tour-started", (e) => {
|
|
503
|
+
console.log("Tour configuration:", e.detail.config);
|
|
508
504
|
});
|
|
509
505
|
|
|
510
|
-
tour.addEventListener(
|
|
511
|
-
console.log(
|
|
506
|
+
tour.addEventListener("scene-loading", (e) => {
|
|
507
|
+
console.log("Loading scene:", e.detail.sceneId);
|
|
512
508
|
// Show loading indicator
|
|
513
509
|
});
|
|
514
510
|
|
|
515
|
-
tour.addEventListener(
|
|
516
|
-
console.log(
|
|
511
|
+
tour.addEventListener("scene-loaded", (e) => {
|
|
512
|
+
console.log("Loaded:", e.detail.sceneName);
|
|
517
513
|
// Hide loading indicator
|
|
518
514
|
});
|
|
519
515
|
|
|
520
|
-
tour.addEventListener(
|
|
521
|
-
console.log(
|
|
522
|
-
console.log(
|
|
516
|
+
tour.addEventListener("hotspot-activated", (e) => {
|
|
517
|
+
console.log("Hotspot clicked:", e.detail.hotspotId);
|
|
518
|
+
console.log("Navigating to:", e.detail.action.target);
|
|
523
519
|
});
|
|
524
520
|
|
|
525
521
|
// Start the tour
|
|
@@ -527,7 +523,7 @@ tour.start();
|
|
|
527
523
|
|
|
528
524
|
// Programmatic navigation
|
|
529
525
|
setTimeout(() => {
|
|
530
|
-
tour.navigateTo(
|
|
526
|
+
tour.navigateTo("room2");
|
|
531
527
|
}, 5000);
|
|
532
528
|
|
|
533
529
|
// Cleanup
|
|
@@ -537,6 +533,7 @@ setTimeout(() => {
|
|
|
537
533
|
## Editor Features
|
|
538
534
|
|
|
539
535
|
### Visual Tour Creation
|
|
536
|
+
|
|
540
537
|
- **Click-to-Place Hotspots** - Raycast-based placement on panorama sphere
|
|
541
538
|
- **Real-Time Preview** - Instant A-Frame rendering as you edit
|
|
542
539
|
- **Scene Management** - Add, remove, reorder scenes with thumbnails
|
|
@@ -544,19 +541,23 @@ setTimeout(() => {
|
|
|
544
541
|
- **Position Validation** - Hotspots clamped to 10-unit sphere radius
|
|
545
542
|
|
|
546
543
|
### Hotspot Configuration
|
|
544
|
+
|
|
547
545
|
- **3D Position** - Click-to-place or manual X/Y/Z coordinate input
|
|
548
546
|
- **Navigation Target** - Link to any scene in the tour
|
|
549
547
|
- **Visual Customization** - Color picker and scale slider
|
|
550
548
|
- **Tooltips** - Custom hover text for each hotspot
|
|
551
549
|
|
|
552
550
|
### Data Management
|
|
551
|
+
|
|
553
552
|
- **LocalStorage Persistence** - Auto-save projects (configurable interval)
|
|
554
553
|
- **Import/Export** - Load and save tour JSON configurations
|
|
555
554
|
- **Data URLs** - Panoramas embedded as base64 (no external files needed)
|
|
556
555
|
- **Thumbnail Generation** - Auto-generated scene previews (100x50px)
|
|
557
556
|
|
|
558
557
|
### Export Options
|
|
558
|
+
|
|
559
559
|
1. **JSON Export** - Portable configuration file for library integration
|
|
560
|
+
|
|
560
561
|
- Converts editor's `imageUrl` to library's `panorama` format
|
|
561
562
|
- Compatible with `SWT.Tour` viewer library
|
|
562
563
|
- Use in custom integrations or standalone viewer
|
|
@@ -568,6 +569,7 @@ setTimeout(() => {
|
|
|
568
569
|
- Drag-and-drop ready for distribution
|
|
569
570
|
|
|
570
571
|
### Developer Tools
|
|
572
|
+
|
|
571
573
|
- **ES6 Module Architecture** - Six-controller pattern with clear separation
|
|
572
574
|
- **Sourcemaps** - Debug original ES6 source in browser DevTools
|
|
573
575
|
- **Two Init Modes** - Declarative (HTML) or Programmatic (JS API)
|
|
@@ -576,21 +578,23 @@ setTimeout(() => {
|
|
|
576
578
|
|
|
577
579
|
## Browser Compatibility
|
|
578
580
|
|
|
579
|
-
| Browser
|
|
580
|
-
|
|
581
|
-
| Chrome
|
|
582
|
-
| Firefox
|
|
583
|
-
| Safari
|
|
584
|
-
| Edge
|
|
585
|
-
| Mobile Safari | iOS 14+
|
|
586
|
-
| Chrome Mobile | Android 90+ | Touch and gyroscope support
|
|
581
|
+
| Browser | Version | Notes |
|
|
582
|
+
| ------------- | ----------- | ------------------------------ |
|
|
583
|
+
| Chrome | 90+ | Recommended - best performance |
|
|
584
|
+
| Firefox | 88+ | Full support |
|
|
585
|
+
| Safari | 14+ | WebGL support required |
|
|
586
|
+
| Edge | 90+ | Chromium-based |
|
|
587
|
+
| Mobile Safari | iOS 14+ | Touch and gyroscope support |
|
|
588
|
+
| Chrome Mobile | Android 90+ | Touch and gyroscope support |
|
|
587
589
|
|
|
588
590
|
**Requirements:**
|
|
591
|
+
|
|
589
592
|
- WebGL 1.0 or higher
|
|
590
593
|
- ES6 module support (for editor)
|
|
591
594
|
- LocalStorage (for editor persistence)
|
|
592
595
|
|
|
593
596
|
**VR Headsets:**
|
|
597
|
+
|
|
594
598
|
- Oculus Quest 1/2/3
|
|
595
599
|
- Meta Quest Pro
|
|
596
600
|
- HTC Vive
|
|
@@ -612,37 +616,6 @@ Contributions are welcome! Here's how you can help:
|
|
|
612
616
|
3. **Submit PRs** - Fork, create a feature branch, and submit a pull request
|
|
613
617
|
4. **Improve Docs** - Help make documentation clearer and more comprehensive
|
|
614
618
|
|
|
615
|
-
### Development Workflow
|
|
616
|
-
|
|
617
|
-
```bash
|
|
618
|
-
# Fork and clone the repository
|
|
619
|
-
git clone https://github.com/your-username/senangwebs-tour.git
|
|
620
|
-
cd senangwebs-tour
|
|
621
|
-
|
|
622
|
-
# Install dependencies
|
|
623
|
-
npm install
|
|
624
|
-
|
|
625
|
-
# Start development server with watch mode
|
|
626
|
-
npm run dev
|
|
627
|
-
|
|
628
|
-
# In another terminal, serve the examples
|
|
629
|
-
npm run serve
|
|
630
|
-
|
|
631
|
-
# Make changes, test in browser at http://localhost:8080
|
|
632
|
-
# Build for production
|
|
633
|
-
npm run build
|
|
634
|
-
|
|
635
|
-
# Submit a pull request
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
### Code Guidelines
|
|
639
|
-
- Use ES6+ syntax (modules, classes, arrow functions)
|
|
640
|
-
- Follow existing naming conventions (see copilot-instructions.md)
|
|
641
|
-
- No debug `console.log()` - only `console.error()` for critical errors
|
|
642
|
-
- All editor classes must use `export default`
|
|
643
|
-
- Debounce text inputs (300ms) using `debounce()` from utils.js
|
|
644
|
-
- Test in Chrome, Firefox, and Safari before submitting
|
|
645
|
-
|
|
646
619
|
## License
|
|
647
620
|
|
|
648
621
|
MIT License - see [LICENSE.md](./LICENSE.md) for details.
|