3D球形實景-熱點追蹤
# FastWeb 全景瀏覽-立方全景圖-熱點追蹤
egjs-view360是全景顯示的庫,可用於展示360環繞全景影像或球形全景影像,在移動設備上支援陀螺儀顯示,可帶給使用者身臨其境的感受。本示例將引入立方環繞全景示例,帶大家瞭解如何使用以及製作可移動的動態全景示意圖。
# 1. 下載示例
點選https://naver.github.io/egjs-view360/release/latest/dist/PanoViewer/view360.panoviewer.pkgd.min.js (opens new window)以下載庫js檔案,在library/js
中建立目錄egjs-view360
,將下載的js檔案放置於此。
# 2. 確認參數
使用的線上示例的樣式內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hot Spot</title>
<link rel="stylesheet" type="text/css" href="https://naver.github.io/egjs-view360/common/css/demo.css">
<link rel="stylesheet" type="text/css" href="https://naver.github.io/egjs-view360/common/css/PanoControls.css">
<script src="https://naver.github.io/egjs-view360/release/latest/dist/PanoViewer/view360.panoviewer.pkgd.min.js"></script>
<script src="https://naver.github.io/egjs-view360/common/js/PanoControls.js"></script>
<script src="https://naver.github.io/egjs-view360/common/js/PieView.js"></script>
<script src="https://naver.github.io/egjs-view360/common/js/jquery-2.2.4.js"></script>
<script src="https://naver.github.io/egjs-view360/common/js/screenfull.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9.7.2/dist/sweetalert2.all.min.js"></script>
<style>
.icon {
background: #70B5E0;
border-radius: 50%;
box-shadow: inset -15px -15px 0px 0px rgba(0, 0, 0, 0.1);
}
.anchor {
position: absolute;
width: 24px;
height: 24px;
background: #f77;
border-radius: 50%;
transform: translate(-50%, -50%);
animation: anchor 10s both infinite;
}
.place {
position: absolute;
width: 20px;
height: 13px;
background: #F2DDAA;
border-radius: 50%;
transform: translate(-50%, -50%);
}
.anchor:before {
position: absolute;
content: "";
top: 70%;
left: 50%;
transform: translate(-50%, 0);
border-top: 13px solid #f77;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
.anchor:after {
position: absolute;
content: "";
width: 30%;
height: 30%;
background: white;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.place1 {
top: 77%;
left: 64%;
}
.place2 {
width: 17px;
height: 10px;
top: 67%;
left: 25%;
}
.place3 {
width: 17px;
height: 10px;
top: 36%;
left: 75%;
}
.place4 {
width: 17px;
height: 10px;
top: 26%;
left: 35%;
}
.anchor1 {
top: 55%;
left: 65%;
animation-delay: 0.3s;
}
.anchor2 {
top: 50%;
left: 25%;
transform: translate(-50%, -50%) scale(0.8);
animation-delay: 0.6s;
}
.anchor3 {
top: 20%;
left: 75%;
transform: translate(-50%, -50%) scale(0.8);
animation-delay: 0.9s;
}
.anchor4 {
top: 10%;
left: 35%;
transform: translate(-50%, -50%) scale(0.7);
animation-delay: 1.2s;
}
@keyframes anchor {
0% {
opacity: 0;
margin-top: -20px;
}
10% {
opacity: 1;
margin-top: 0px;
}
85% {
opacity: 1;
margin-top: 0px;
}
91% {
opacity: 0;
margin-top: -20px;
}
100% {
opacity: 0;
margin-top: -20px;
}
}
.hotspot {
position: absolute;
top: 0;
left: 0;
display: none;
z-index: 2;
}
.hotspot.search {
width: 24px;
height: 24px;
/* border: 1px solid #fff; */
}
.hotspot.search:before {
position: absolute;
content: "";
width: 12px;
height: 12px;
top: 0px;
left: 0px;
border-radius: 50%;
border: 3px solid #fff;
}
.hotspot.search:after {
position: absolute;
content: "";
top: 14px;
left: 14px;
width: 3px;
height: 8px;
background: #fff;
transform-origin: 50% 0%;
transform: rotate(-45deg);
}
.hotspot.link {
text-align: center;
font-weight: bold;
color: #fff;
}
.viewer[data-page="1"] .hotspot[data-page="1"] {
display: block;
}
.viewer[data-page="2"] .hotspot[data-page="2"] {
display: block;
}
.layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 4;
display: none;
}
.layer img {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<div class="viewer" data-page="1">
<div class="container"></div>
<div class="layer" onclick="closeLayer(event);">
<img src="https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/book1.jpg">
</div>
<div class="hotspot search" data-page="1" data-anchor-index="0" data-yaw="52" data-pitch="-14" onclick="openLayer('book1.jpg')"></div>
<div class="hotspot search" data-page="1" data-anchor-index="1" data-yaw="-45" data-pitch="-18" onclick="openLayer('book2.jpg')"></div>
<div class="hotspot search" data-page="1" data-anchor-index="2" data-yaw="6" data-pitch="-17" onclick="openLayer('book3.jpg')"></div>
<div class="hotspot link" data-page="1" data-anchor-index="3" data-yaw="-96" data-pitch="-8" onclick="load(this, 2)">
Economy<br>
Culture
</div>
<div class="hotspot search" data-page="2" data-anchor-index="0" data-yaw="-60" data-pitch="-23" onclick="openLayer('book4.jpg')"></div>
<div class="hotspot link" data-page="2" data-anchor-index="1" data-yaw="80" data-pitch="-12" onclick="load(this, 1)">
Technology<br>Science
</div>
</div>
<script>
var layer = document.querySelector(".layer");
var panoviewer = document.querySelector(".viewer");
var container = document.querySelector(".viewer .container");
var hotspots = Array.prototype.slice.call(document.querySelectorAll(".hotspot"));
var currentPage = "1";
function openLayer(img) {
layer.querySelector("img").src = "https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/" + img;
layer.style.display = "block";
}
function closeLayer(e) {
if (e.target === layer) {
layer.style.display = "none";
}
}
function toRadian(deg) {
return deg * Math.PI / 180;
}
function getHFov(fov) {
var rect = container.getBoundingClientRect();
var width = rect.width;
var height = rect.height;
return Math.atan(width / height * Math.tan(toRadian(fov) / 2)) / Math.PI * 360;
}
function rotate(point, deg) {
var rad = toRadian(deg);
var cos = Math.cos(rad);
var sin = Math.sin(rad);
return [cos * point[0] - sin * point[1], sin * point[0] + cos * point[1]];
}
function setHotspotOffset(hotspot, viewer) {
var oyaw = viewer.getYaw();
var opitch = viewer.getPitch();
var yaw = parseFloat(hotspot.getAttribute("data-yaw"));
var pitch = parseFloat(hotspot.getAttribute("data-pitch"));
var deltaYaw = yaw - oyaw;
var deltaPitch = pitch - opitch;
if (deltaYaw < -180) {
deltaYaw += 360;
} else if (deltaYaw > 180) {
deltaYaw -= 360;
}
if (Math.abs(deltaYaw) > 90) {
hotspot.style.transform = "translate(-200px, 0px)";
return;
}
var radYaw = toRadian(deltaYaw);
var radPitch = toRadian(deltaPitch);
var fov = viewer.getFov();
var hfov = getHFov(fov);
var rx = Math.tan(toRadian(hfov) / 2);
var ry = Math.tan(toRadian(fov) / 2);
var point = [
Math.tan(-radYaw) / rx,
Math.tan(-radPitch) / ry,
];
// Image rotation compensation
// The original image is about 10 degrees tilted.
point = point.map(function (p) {
return p * Math.cos(15 / 180 * Math.PI);
});
point[1] = rotate(point, deltaYaw > 0 ? -10 : 10)[1];
// point[0] /= 1.05;
var left = viewer._width / 2 + point[0] * viewer._width / 2;
var top = viewer._height / 2 + point[1] * viewer._height / 2;
hotspot.style.transform = "translate(" + left + "px, " + top + "px) translate(-50%, -50%)";
}
function setHotspotOffsets(viewer) {
hotspots.filter(function (hotspot) {
return hotspot.getAttribute("data-page") === currentPage;
}).forEach(function (hotspot) {
setHotspotOffset(hotspot, viewer);
});
}
function load(target, page) {
if (currentPage == page) {
return;
}
var yaw = target.getAttribute("data-yaw");
var pitch = target.getAttribute("data-pitch");
currentPage = "" + page;
viewer.lookAt({
yaw: yaw,
pitch: pitch,
fov: 30
}, 500);
setTimeout(function () {
panoviewer.setAttribute("data-page", currentPage);
viewer.setImage("https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/bookcube" + page + ".jpg", {
projectionType: eg.view360.PanoViewer.PROJECTION_TYPE.CUBEMAP,
cubemapConfig: {
tileConfig: { flipHorizontal: true, rotation: 0 },
}
});
}, 500);
}
var viewer = new eg.view360.PanoViewer(container, {
image: "https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/bookcube1.jpg",
useZoom: false,
projectionType: eg.view360.PanoViewer.PROJECTION_TYPE.CUBEMAP,
cubemapConfig: {
tileConfig: { flipHorizontal: true, rotation: 0 },
}
}).on("ready", function (e) {
viewer.lookAt({
fov: 80,
});
setTimeout(function () {
viewer.lookAt({
fov: 65,
}, 500);
setHotspotOffsets(viewer);
});
}).on("viewChange", function (e) {
setHotspotOffsets(viewer);
}).on("error", function (e) {
console.error(e);
});
window.addEventListener("resize", function (e) {
viewer.updateViewportDimensions();
setHotspotOffsets(viewer);
});
PanoControls.init(panoviewer, viewer);
PanoControls.showLoading();
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# 3. 修改模板
# 3.1. 本地化處理
可以看到上述的html文件中引入了外部鏈接庫檔案,將整理的以下鏈接指向的檔案下載下來並按照指示放入指定目錄中。
以下檔案請放入library/js/egjs-view360/common/css/目錄
https://naver.github.io/egjs-view360/common/css/demo.css
https://naver.github.io/egjs-view360/common/css/PanoControls.css
以下檔案請放入library/js/egjs-view360/common/js/目錄
https://naver.github.io/egjs-view360/common/js/PanoControls.js
https://naver.github.io/egjs-view360/common/js/PieView.js
https://naver.github.io/egjs-view360/common/js/jquery-2.2.4.js
https://naver.github.io/egjs-view360/common/js/screenfull.min.js
https://cdn.jsdelivr.net/npm/sweetalert2@9.7.2/dist/sweetalert2.all.min.js
以下檔案下載下來后請將檔案放入library/js/egjs-view360/examples/img
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/book1.jpg
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/book2.jpg
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/book3.jpg
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/book4.jpg
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/bookcube1.jpg
https://naver.github.io/egjs-view360/examples/panoviewer/etc/img/bookcube2.jpg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
部分庫檔案需依賴圖示檔案,從以下地址下載圖示檔案並將其放入指定目錄中。
以下檔案請放入library/js/egjs-view360/common/img/目錄
https://naver.github.io/egjs-view360/common/img/sp_component.png
https://naver.github.io/egjs-view360/common/img/common_loading_mo_white.gif
1
2
3
2
3
將html文件中對應的鏈接修改爲本地的相對鏈接,修改後的示例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hot Spot</title>
<link rel="stylesheet" type="text/css" href="library/js/egjs-view360/common/css/demo.css">
<link rel="stylesheet" type="text/css" href="library/js/egjs-view360/common/css/PanoControls.css">
<script src="library/js/egjs-view360/view360.panoviewer.pkgd.min.js"></script>
<script src="library/js/egjs-view360/common/js/PanoControls.js"></script>
<script src="library/js/egjs-view360/common/js/PieView.js"></script>
<script src="library/js/egjs-view360/common/js/jquery-2.2.4.js"></script>
<script src="library/js/egjs-view360/common/js/screenfull.min.js"></script>
<script src="library/js/egjs-view360/common/js/sweetalert2.all.min.js"></script>
<style>
.icon {
background: #70B5E0;
border-radius: 50%;
box-shadow: inset -15px -15px 0px 0px rgba(0, 0, 0, 0.1);
}
.anchor {
position: absolute;
width: 24px;
height: 24px;
background: #f77;
border-radius: 50%;
transform: translate(-50%, -50%);
animation: anchor 10s both infinite;
}
.place {
position: absolute;
width: 20px;
height: 13px;
background: #F2DDAA;
border-radius: 50%;
transform: translate(-50%, -50%);
}
.anchor:before {
position: absolute;
content: "";
top: 70%;
left: 50%;
transform: translate(-50%, 0);
border-top: 13px solid #f77;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
.anchor:after {
position: absolute;
content: "";
width: 30%;
height: 30%;
background: white;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.place1 {
top: 77%;
left: 64%;
}
.place2 {
width: 17px;
height: 10px;
top: 67%;
left: 25%;
}
.place3 {
width: 17px;
height: 10px;
top: 36%;
left: 75%;
}
.place4 {
width: 17px;
height: 10px;
top: 26%;
left: 35%;
}
.anchor1 {
top: 55%;
left: 65%;
animation-delay: 0.3s;
}
.anchor2 {
top: 50%;
left: 25%;
transform: translate(-50%, -50%) scale(0.8);
animation-delay: 0.6s;
}
.anchor3 {
top: 20%;
left: 75%;
transform: translate(-50%, -50%) scale(0.8);
animation-delay: 0.9s;
}
.anchor4 {
top: 10%;
left: 35%;
transform: translate(-50%, -50%) scale(0.7);
animation-delay: 1.2s;
}
@keyframes anchor {
0% {
opacity: 0;
margin-top: -20px;
}
10% {
opacity: 1;
margin-top: 0px;
}
85% {
opacity: 1;
margin-top: 0px;
}
91% {
opacity: 0;
margin-top: -20px;
}
100% {
opacity: 0;
margin-top: -20px;
}
}
.hotspot {
position: absolute;
top: 0;
left: 0;
display: none;
z-index: 2;
}
.hotspot.search {
width: 24px;
height: 24px;
/* border: 1px solid #fff; */
}
.hotspot.search:before {
position: absolute;
content: "";
width: 12px;
height: 12px;
top: 0px;
left: 0px;
border-radius: 50%;
border: 3px solid #fff;
}
.hotspot.search:after {
position: absolute;
content: "";
top: 14px;
left: 14px;
width: 3px;
height: 8px;
background: #fff;
transform-origin: 50% 0%;
transform: rotate(-45deg);
}
.hotspot.link {
text-align: center;
font-weight: bold;
color: #fff;
}
.viewer[data-page="1"] .hotspot[data-page="1"] {
display: block;
}
.viewer[data-page="2"] .hotspot[data-page="2"] {
display: block;
}
.layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 4;
display: none;
}
.layer img {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<div class="viewer" data-page="1">
<div class="container"></div>
<div class="layer" onclick="closeLayer(event);">
<img src="library/js/egjs-view360/examples/img/book1.jpg">
</div>
<div class="hotspot search" data-page="1" data-anchor-index="0" data-yaw="52" data-pitch="-14" onclick="openLayer('book1.jpg')"></div>
<div class="hotspot search" data-page="1" data-anchor-index="1" data-yaw="-45" data-pitch="-18" onclick="openLayer('book2.jpg')"></div>
<div class="hotspot search" data-page="1" data-anchor-index="2" data-yaw="6" data-pitch="-17" onclick="openLayer('book3.jpg')"></div>
<div class="hotspot link" data-page="1" data-anchor-index="3" data-yaw="-96" data-pitch="-8" onclick="load(this, 2)">
Economy<br>
Culture
</div>
<div class="hotspot search" data-page="2" data-anchor-index="0" data-yaw="-60" data-pitch="-23" onclick="openLayer('book4.jpg')"></div>
<div class="hotspot link" data-page="2" data-anchor-index="1" data-yaw="80" data-pitch="-12" onclick="load(this, 1)">
Technology<br>Science
</div>
</div>
<script>
var layer = document.querySelector(".layer");
var panoviewer = document.querySelector(".viewer");
var container = document.querySelector(".viewer .container");
var hotspots = Array.prototype.slice.call(document.querySelectorAll(".hotspot"));
var currentPage = "1";
function openLayer(img) {
layer.querySelector("img").src = "library/js/egjs-view360/examples/img/" + img;
layer.style.display = "block";
}
function closeLayer(e) {
if (e.target === layer) {
layer.style.display = "none";
}
}
function toRadian(deg) {
return deg * Math.PI / 180;
}
function getHFov(fov) {
var rect = container.getBoundingClientRect();
var width = rect.width;
var height = rect.height;
return Math.atan(width / height * Math.tan(toRadian(fov) / 2)) / Math.PI * 360;
}
function rotate(point, deg) {
var rad = toRadian(deg);
var cos = Math.cos(rad);
var sin = Math.sin(rad);
return [cos * point[0] - sin * point[1], sin * point[0] + cos * point[1]];
}
function setHotspotOffset(hotspot, viewer) {
var oyaw = viewer.getYaw();
var opitch = viewer.getPitch();
var yaw = parseFloat(hotspot.getAttribute("data-yaw"));
var pitch = parseFloat(hotspot.getAttribute("data-pitch"));
var deltaYaw = yaw - oyaw;
var deltaPitch = pitch - opitch;
if (deltaYaw < -180) {
deltaYaw += 360;
} else if (deltaYaw > 180) {
deltaYaw -= 360;
}
if (Math.abs(deltaYaw) > 90) {
hotspot.style.transform = "translate(-200px, 0px)";
return;
}
var radYaw = toRadian(deltaYaw);
var radPitch = toRadian(deltaPitch);
var fov = viewer.getFov();
var hfov = getHFov(fov);
var rx = Math.tan(toRadian(hfov) / 2);
var ry = Math.tan(toRadian(fov) / 2);
var point = [
Math.tan(-radYaw) / rx,
Math.tan(-radPitch) / ry,
];
point = point.map(function (p) {
return p * Math.cos(15 / 180 * Math.PI);
});
point[1] = rotate(point, deltaYaw > 0 ? -10 : 10)[1];
var left = viewer._width / 2 + point[0] * viewer._width / 2;
var top = viewer._height / 2 + point[1] * viewer._height / 2;
hotspot.style.transform = "translate(" + left + "px, " + top + "px) translate(-50%, -50%)";
}
function setHotspotOffsets(viewer) {
hotspots.filter(function (hotspot) {
return hotspot.getAttribute("data-page") === currentPage;
}).forEach(function (hotspot) {
setHotspotOffset(hotspot, viewer);
});
}
function load(target, page) {
if (currentPage == page) {
return;
}
var yaw = target.getAttribute("data-yaw");
var pitch = target.getAttribute("data-pitch");
currentPage = "" + page;
viewer.lookAt({
yaw: yaw,
pitch: pitch,
fov: 30
}, 500);
setTimeout(function () {
panoviewer.setAttribute("data-page", currentPage);
viewer.setImage("library/js/egjs-view360/examples/img/bookcube" + page + ".jpg", {
projectionType: eg.view360.PanoViewer.PROJECTION_TYPE.CUBEMAP,
cubemapConfig: {
tileConfig: { flipHorizontal: true, rotation: 0 },
}
});
}, 500);
}
var viewer = new eg.view360.PanoViewer(container, {
image: "library/js/egjs-view360/examples/img/bookcube1.jpg",
useZoom: false,
projectionType: eg.view360.PanoViewer.PROJECTION_TYPE.CUBEMAP,
cubemapConfig: {
tileConfig: { flipHorizontal: true, rotation: 0 },
}
}).on("ready", function (e) {
viewer.lookAt({
fov: 80,
});
setTimeout(function () {
viewer.lookAt({
fov: 65,
}, 500);
setHotspotOffsets(viewer);
});
}).on("viewChange", function (e) {
setHotspotOffsets(viewer);
}).on("error", function (e) {
console.error(e);
});
window.addEventListener("resize", function (e) {
viewer.updateViewportDimensions();
setHotspotOffsets(viewer);
});
PanoControls.init(panoviewer, viewer);
PanoControls.showLoading();
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
可進入JQueryFrame元件管理界面,將上述內容填寫入模板中。此庫由於引用了較多的外部的css與js檔案,為保證其不被FastWeb框架影響,建議使用URLFrame容器引入。
# 4. 設定檔案
全景瀏覽的初始示例使用的相片為立方全景影象,此影象通常由球狀全景影象轉換而來。可參考全景瀏覽-球狀全景圖-汽車內飾中的球狀全景圖製作方式製作球狀全景圖,然後再使用PTGui將球狀全景圖轉換為立方全景圖。