@qispace/vue3-player 0.0.5

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.
Files changed (160) hide show
  1. package/README.md +18 -0
  2. package/dist/components/apartmentChooser/QiApartmentChooser.vue.d.ts +4 -0
  3. package/dist/components/apartmentChooser/QiApartmentChooser.vue.d.ts.map +1 -0
  4. package/dist/components/apartmentChooser/QiApartmentChooserNavigation.vue.d.ts +4 -0
  5. package/dist/components/apartmentChooser/QiApartmentChooserNavigation.vue.d.ts.map +1 -0
  6. package/dist/components/apartmentChooser/QiApartmentChooserRaster.vue.d.ts +4 -0
  7. package/dist/components/apartmentChooser/QiApartmentChooserRaster.vue.d.ts.map +1 -0
  8. package/dist/components/apartmentChooser/QiApartmentChooserRotator.vue.d.ts +4 -0
  9. package/dist/components/apartmentChooser/QiApartmentChooserRotator.vue.d.ts.map +1 -0
  10. package/dist/components/apartmentChooser/QiApartmentChooserSvg.vue.d.ts +4 -0
  11. package/dist/components/apartmentChooser/QiApartmentChooserSvg.vue.d.ts.map +1 -0
  12. package/dist/components/buildingPicker/QiBuildingChooser.vue.d.ts +3 -0
  13. package/dist/components/buildingPicker/QiBuildingChooser.vue.d.ts.map +1 -0
  14. package/dist/components/buildingPicker/QiBuildingChooserRaster.vue.d.ts +4 -0
  15. package/dist/components/buildingPicker/QiBuildingChooserRaster.vue.d.ts.map +1 -0
  16. package/dist/components/buildingPicker/QiBuildingChooserRasterOverlay.vue.d.ts +4 -0
  17. package/dist/components/buildingPicker/QiBuildingChooserRasterOverlay.vue.d.ts.map +1 -0
  18. package/dist/components/buildingPicker/QiBuildingChooserSceneImageStack.vue.d.ts +4 -0
  19. package/dist/components/buildingPicker/QiBuildingChooserSceneImageStack.vue.d.ts.map +1 -0
  20. package/dist/components/buildingPicker/QiBuildingChooserSunSimControl.vue.d.ts +5 -0
  21. package/dist/components/buildingPicker/QiBuildingChooserSunSimControl.vue.d.ts.map +1 -0
  22. package/dist/components/buildingPicker/QiBuildingChooserSvg.vue.d.ts +4 -0
  23. package/dist/components/buildingPicker/QiBuildingChooserSvg.vue.d.ts.map +1 -0
  24. package/dist/components/index.d.ts +4 -0
  25. package/dist/components/shared/QiFloatingCard.vue.d.ts +4 -0
  26. package/dist/components/shared/QiFloatingCard.vue.d.ts.map +1 -0
  27. package/dist/components/shared/QiHoverProbe.vue.d.ts +4 -0
  28. package/dist/components/shared/QiHoverProbe.vue.d.ts.map +1 -0
  29. package/dist/components/shared/QiNorthDirection.vue.d.ts +3 -0
  30. package/dist/components/shared/QiNorthDirection.vue.d.ts.map +1 -0
  31. package/dist/components/shared/QiZoomBox.vue.d.ts +4 -0
  32. package/dist/components/shared/QiZoomBox.vue.d.ts.map +1 -0
  33. package/dist/components/virtualTourV2/Disclaimer.vue.d.ts +4 -0
  34. package/dist/components/virtualTourV2/Disclaimer.vue.d.ts.map +1 -0
  35. package/dist/components/virtualTourV2/FullScreenButton.vue.d.ts +3 -0
  36. package/dist/components/virtualTourV2/FullScreenButton.vue.d.ts.map +1 -0
  37. package/dist/components/virtualTourV2/ManualSlideShow.vue.d.ts +4 -0
  38. package/dist/components/virtualTourV2/ManualSlideShow.vue.d.ts.map +1 -0
  39. package/dist/components/virtualTourV2/ManualSlideShowPlayer.vue.d.ts +4 -0
  40. package/dist/components/virtualTourV2/ManualSlideShowPlayer.vue.d.ts.map +1 -0
  41. package/dist/components/virtualTourV2/SingleImage.vue.d.ts +4 -0
  42. package/dist/components/virtualTourV2/SingleImage.vue.d.ts.map +1 -0
  43. package/dist/components/virtualTourV2/SocialShare.vue.d.ts +4 -0
  44. package/dist/components/virtualTourV2/SocialShare.vue.d.ts.map +1 -0
  45. package/dist/components/virtualTourV2/WaypointCarousel.vue.d.ts +4 -0
  46. package/dist/components/virtualTourV2/WaypointCarousel.vue.d.ts.map +1 -0
  47. package/dist/lib/virtualTour__/ApartmentConfig.d.ts +27 -0
  48. package/dist/lib/virtualTour__/ApartmentFiles.d.ts +7 -0
  49. package/dist/lib/virtualTour__/MinimapConfig.d.ts +23 -0
  50. package/dist/lib/virtualTour__/impl/HttpApartmentFiles.d.ts +19 -0
  51. package/dist/vue3-player.cjs.js +2 -0
  52. package/dist/vue3-player.esm.js +2992 -0
  53. package/dist/vue3-player.iife.js +3 -0
  54. package/dist/vue3-player.umd.js +3 -0
  55. package/package.json +65 -0
  56. package/src/components/apartmentChooser/QiApartmentChooser.vue +319 -0
  57. package/src/components/apartmentChooser/QiApartmentChooserNavigation.vue +88 -0
  58. package/src/components/apartmentChooser/QiApartmentChooserRaster.vue +408 -0
  59. package/src/components/apartmentChooser/QiApartmentChooserRotator.vue +202 -0
  60. package/src/components/apartmentChooser/QiApartmentChooserSvg.vue +257 -0
  61. package/src/components/apartmentChooser/index.js +5 -0
  62. package/src/components/buildingPicker/QiBuildingChooser.vue +61 -0
  63. package/src/components/buildingPicker/QiBuildingChooserRaster.vue +312 -0
  64. package/src/components/buildingPicker/QiBuildingChooserRasterOverlay.vue +96 -0
  65. package/src/components/buildingPicker/QiBuildingChooserSceneImageStack.vue +89 -0
  66. package/src/components/buildingPicker/QiBuildingChooserSunSimControl.vue +257 -0
  67. package/src/components/buildingPicker/QiBuildingChooserSvg.vue +414 -0
  68. package/src/components/buildingPicker/index.js +6 -0
  69. package/src/components/index.ts +4 -0
  70. package/src/components/shared/QiFloatingCard.vue +76 -0
  71. package/src/components/shared/QiHoverProbe.vue +22 -0
  72. package/src/components/shared/QiNorthDirection.vue +27 -0
  73. package/src/components/shared/QiZoomBox.vue +322 -0
  74. package/src/components/shared/index.js +4 -0
  75. package/src/components/virtualTourV2/Compass.vue +37 -0
  76. package/src/components/virtualTourV2/Disclaimer.vue +41 -0
  77. package/src/components/virtualTourV2/FloorLevel.vue +73 -0
  78. package/src/components/virtualTourV2/FullScreenButton.vue +23 -0
  79. package/src/components/virtualTourV2/InteriorSelector.vue +90 -0
  80. package/src/components/virtualTourV2/ManualSlideShow.vue +198 -0
  81. package/src/components/virtualTourV2/ManualSlideShowPlayer.vue +159 -0
  82. package/src/components/virtualTourV2/PlayerV2.vue +300 -0
  83. package/src/components/virtualTourV2/ScrollHelper.vue +74 -0
  84. package/src/components/virtualTourV2/SettingsUI.vue +355 -0
  85. package/src/components/virtualTourV2/SingleImage.vue +36 -0
  86. package/src/components/virtualTourV2/SocialShare.vue +163 -0
  87. package/src/components/virtualTourV2/TimeOfDay.vue +50 -0
  88. package/src/components/virtualTourV2/Tutorial.vue +690 -0
  89. package/src/components/virtualTourV2/ViewModeToggle.vue +24 -0
  90. package/src/components/virtualTourV2/VirtualTourV2.vue +876 -0
  91. package/src/components/virtualTourV2/WaypointCarousel.vue +162 -0
  92. package/src/components/virtualTourV2/index.js +1 -0
  93. package/src/components/virtualTourV2/minimapv2/MiniMapMap.vue +262 -0
  94. package/src/components/virtualTourV2/minimapv2/MiniMapV2.vue +110 -0
  95. package/src/components/virtualTourV2/minimapv2/MinimapCompass.vue +39 -0
  96. package/src/components/virtualTourV2/minimapv2/Moveable.vue +208 -0
  97. package/src/components/virtualTourV2/minimapv2/RotationMarkerV2.vue +79 -0
  98. package/src/components/virtualTourV2/minimapv2/SunsimulationSlider.vue +203 -0
  99. package/src/components/virtualTourV2/minimapv2/index.js +1 -0
  100. package/src/entry.esm.js +17 -0
  101. package/src/entry.js +13 -0
  102. package/src/entry.ts_ +17 -0
  103. package/src/lib/apartmentChooser/BuildingViewerModel.js +60 -0
  104. package/src/lib/apartmentChooser/CircularSlideshow.js +66 -0
  105. package/src/lib/apartmentChooser/RotationStep.js +31 -0
  106. package/src/lib/apartmentChooser/SceneRotator.js +25 -0
  107. package/src/lib/apartmentChooser/index.js +3 -0
  108. package/src/lib/apartmentChooser/throttle.js +15 -0
  109. package/src/lib/buildingPicker/BuildingMap.js +24 -0
  110. package/src/lib/buildingPicker/BuildingPickerResourceProvider.js +97 -0
  111. package/src/lib/buildingPicker/CanvasRaster.js +29 -0
  112. package/src/lib/buildingPicker/DayOfYearSelector.js +36 -0
  113. package/src/lib/buildingPicker/SampleRaster.js +14 -0
  114. package/src/lib/buildingPicker/index.js +5 -0
  115. package/src/lib/index.js +4 -0
  116. package/src/lib/shared/BatchLoadTracker.js +52 -0
  117. package/src/lib/shared/I18N.js +65 -0
  118. package/src/lib/shared/ResourceLoader.js +33 -0
  119. package/src/lib/shared/index.js +3 -0
  120. package/src/lib/virtualTour/CameraSnapshot.js +42 -0
  121. package/src/lib/virtualTour/FullscreenModel.js +69 -0
  122. package/src/lib/virtualTour/textures/arrow.png +0 -0
  123. package/src/lib/virtualTour/textures/compass-bg.png +0 -0
  124. package/src/lib/virtualTour/textures/compass-needle.png +0 -0
  125. package/src/lib/virtualTour/textures/compass-north.png +0 -0
  126. package/src/lib/virtualTour/textures/floor-1.svg +4 -0
  127. package/src/lib/virtualTour/textures/floor-2.svg +4 -0
  128. package/src/lib/virtualTour/textures/marker.png +0 -0
  129. package/src/lib/virtualTour/textures/tod-sun.png +0 -0
  130. package/src/lib/virtualTour__/ApartmentConfig.ts +80 -0
  131. package/src/lib/virtualTour__/ApartmentFiles.ts +8 -0
  132. package/src/lib/virtualTour__/CameraNavigator.js_ +74 -0
  133. package/src/lib/virtualTour__/CameraSnapshot.js +42 -0
  134. package/src/lib/virtualTour__/CoordConversions.js +43 -0
  135. package/src/lib/virtualTour__/FullscreenModel.js +69 -0
  136. package/src/lib/virtualTour__/MinimapConfig.ts +46 -0
  137. package/src/lib/virtualTour__/PlayerViewModel.js +423 -0
  138. package/src/lib/virtualTour__/config/ApartmentConfig.js +92 -0
  139. package/src/lib/virtualTour__/config/CameraConfig.js +97 -0
  140. package/src/lib/virtualTour__/config/Interaction.js +393 -0
  141. package/src/lib/virtualTour__/config/Panorama.js +78 -0
  142. package/src/lib/virtualTour__/config/PlayerConfig.js +812 -0
  143. package/src/lib/virtualTour__/config/rawinflate.export.js +833 -0
  144. package/src/lib/virtualTour__/config/shaders.js +24 -0
  145. package/src/lib/virtualTour__/impl/HttpApartmentFiles.ts +57 -0
  146. package/src/lib/virtualTour__/index.js +1 -0
  147. package/src/lib/virtualTour__/textures/arrow.png +0 -0
  148. package/src/lib/virtualTour__/textures/compass-bg.png +0 -0
  149. package/src/lib/virtualTour__/textures/compass-needle.png +0 -0
  150. package/src/lib/virtualTour__/textures/compass-north.png +0 -0
  151. package/src/lib/virtualTour__/textures/floor-1.svg +4 -0
  152. package/src/lib/virtualTour__/textures/floor-2.svg +4 -0
  153. package/src/lib/virtualTour__/textures/marker.png +0 -0
  154. package/src/lib/virtualTour__/textures/tod-sun.png +0 -0
  155. package/src/main.ts_ +24 -0
  156. package/src/shims-png.d.ts +4 -0
  157. package/src/shims-tsx.d.ts +11 -0
  158. package/src/shims-vue.d.ts +4 -0
  159. package/src/style.css +0 -0
  160. package/src/vite-env.d.ts +5 -0
@@ -0,0 +1,25 @@
1
+ import { RotationStep } from './RotationStep'
2
+
3
+ export class SceneRotator {
4
+ constructor(cardinalFrames, totalFrameCount) {
5
+ this._cardinalFrames = cardinalFrames
6
+ this._totalFrameCount = totalFrameCount
7
+ }
8
+
9
+ start(direction, fromScene, sceneCount) {
10
+ const startFrame = this.startFrameIndexForScene(fromScene)
11
+ return new RotationStep(this, direction, startFrame, sceneCount)
12
+ }
13
+
14
+ isCardinalFrame(frameIndex) {
15
+ return this._cardinalFrames.includes(frameIndex)
16
+ }
17
+
18
+ clampFrameIndex(frameIndex) {
19
+ return (this._totalFrameCount + frameIndex) % this._totalFrameCount
20
+ }
21
+
22
+ startFrameIndexForScene(sceneIndex) {
23
+ return this._cardinalFrames[sceneIndex]
24
+ }
25
+ }
@@ -0,0 +1,3 @@
1
+ export { BuildingViewerModel } from './BuildingViewerModel'
2
+ export { SceneRotator } from './SceneRotator'
3
+ export { default as throttle } from './throttle'
@@ -0,0 +1,15 @@
1
+ export default {
2
+ methods: {
3
+ throttle(callback, interval) {
4
+ let enableCall = true
5
+
6
+ return function (...args) {
7
+ if (!enableCall) return
8
+
9
+ enableCall = false
10
+ callback.apply(this, args)
11
+ setTimeout(() => (enableCall = true), interval)
12
+ }
13
+ },
14
+ },
15
+ }
@@ -0,0 +1,24 @@
1
+ export class BuildingMap {
2
+ static empty() {
3
+ return new BuildingMap([])
4
+ }
5
+
6
+ constructor(buildingIds) {
7
+ this._buildingIds = buildingIds
8
+ }
9
+
10
+ getBuildingId(raster, x, y) {
11
+ const index = this._getBuildingIndex(raster, x, y)
12
+ if (index === undefined) return undefined
13
+ return this._buildingIds[index]
14
+ }
15
+
16
+ _getBuildingIndex(raster, x, y) {
17
+ const [r, g, b, a] = raster.getPixel(x, y)
18
+ if (a === 255 && r === g && g === b) {
19
+ return r
20
+ } else {
21
+ return undefined
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,97 @@
1
+ import { ResourceLoader } from '../shared/ResourceLoader'
2
+
3
+ const CONFIG_FILENAME = 'buildingChooser.json'
4
+ const DEFAULT_DAY_OF_YEAR = 180
5
+
6
+ export class BuildingPickerResourceProvider {
7
+ constructor(cdnFileResolver) {
8
+ this._cdnFileResolver = cdnFileResolver
9
+ this._resourceLoader = new ResourceLoader()
10
+ }
11
+
12
+ constructFileUrl(filename) {
13
+ return this._cdnFileResolver ? this._cdnFileResolver(`/${filename}`) : null
14
+ }
15
+
16
+ loadConfigFile() {
17
+ const url = this.constructFileUrl(CONFIG_FILENAME)
18
+ return url ? this._resourceLoader.loadJson(url) : null
19
+ }
20
+
21
+ loadBuildingMapImage(config) {
22
+ const url = this.constructFileUrl(config.lookupFilename)
23
+ return url ? this._resourceLoader.loadImage(url) : null
24
+ }
25
+
26
+ getViewLongitude(config) {
27
+ return config.cameraRotation && config.cameraRotation.y + 270
28
+ }
29
+
30
+ getBuildingData(config) {
31
+ const buildings = config ? config.buildings : []
32
+ const buildingIds = buildings.map((b) => b.id)
33
+ const buildingOverlays = buildings.map((b) => ({
34
+ id: b.id,
35
+ url: this.constructFileUrl(b.overlayFilename),
36
+ }))
37
+ return { buildingIds, buildingOverlays }
38
+ }
39
+
40
+ getBackgroundImageData(config) {
41
+ if ('days' in config) {
42
+ return this.processMultipleDays(config.days)
43
+ } else {
44
+ const defaultDayBackgrounds = this.processTimeSamples(
45
+ DEFAULT_DAY_OF_YEAR,
46
+ config.timeSamples
47
+ )
48
+ return [defaultDayBackgrounds]
49
+ }
50
+ }
51
+
52
+ processMultipleDays(dayRecords) {
53
+ return dayRecords.map((record) =>
54
+ this.processTimeSamples(record.dayOfYear, record.timeSamples)
55
+ )
56
+ }
57
+
58
+ processTimeSamples(dayOfYear, timeSamples) {
59
+ const imageUrls = timeSamples.map((ts) =>
60
+ this.constructFileUrl(ts.filename)
61
+ )
62
+ return {
63
+ urls: imageUrls,
64
+ referenceDate: this.makeReferenceDate(dayOfYear),
65
+ }
66
+ }
67
+
68
+ makeReferenceDate(dayOfYear) {
69
+ const refDate = new Date(0)
70
+ refDate.setUTCDate(dayOfYear)
71
+ return refDate
72
+ }
73
+
74
+ async loadBuildingChooser() {
75
+ try {
76
+ const config = await this.loadConfigFile()
77
+ if (config) {
78
+ const mapImage = await this.loadBuildingMapImage(config)
79
+ if (mapImage) {
80
+ const viewLongitude = this.getViewLongitude(config)
81
+ const { buildingIds, buildingOverlays } = this.getBuildingData(config)
82
+ const backgrounds = this.getBackgroundImageData(config)
83
+ return {
84
+ mapImage,
85
+ viewLongitude,
86
+ buildingIds,
87
+ buildingOverlays,
88
+ backgrounds,
89
+ }
90
+ }
91
+ }
92
+ return null
93
+ } catch {
94
+ return null
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,29 @@
1
+ export class CanvasRaster {
2
+ static empty() {
3
+ return new CanvasRaster(null)
4
+ }
5
+
6
+ constructor(mapImage) {
7
+ this._mapImage = mapImage
8
+ this._context = null
9
+ }
10
+
11
+ update(canvas) {
12
+ if (!this._mapImage) return
13
+
14
+ this._context = canvas.getContext('2d', { willReadFrequently: true })
15
+ this._context.drawImage(this._mapImage, 0, 0, canvas.width, canvas.height)
16
+ }
17
+
18
+ getPixel(x, y) {
19
+ try {
20
+ if (!this._context) {
21
+ return [0, 0, 0, 0]
22
+ } else {
23
+ return this._context.getImageData(x, y, 1, 1).data
24
+ }
25
+ } catch {
26
+ return [0, 0, 0, 0]
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,36 @@
1
+ const DEFAULT_DATE = new Date(0)
2
+
3
+ export class DayOfYearSelector {
4
+ static empty() {
5
+ return new DayOfYearSelector([{ referenceDate: DEFAULT_DATE, urls: [] }])
6
+ }
7
+
8
+ constructor(imagesByDay) {
9
+ this._imagesByDay = imagesByDay
10
+ this._state = { selectedIndex: 0 }
11
+ }
12
+
13
+ selectIndex(value) {
14
+ if (value < this._imagesByDay.length) this._state.selectedIndex = value
15
+ }
16
+
17
+ get dates() {
18
+ return this._imagesByDay.map((it) => it.referenceDate)
19
+ }
20
+
21
+ get hasMultipleDates() {
22
+ return this._imagesByDay.length > 1
23
+ }
24
+
25
+ get selectedIndex() {
26
+ return this._state.selectedIndex
27
+ }
28
+
29
+ get selectedDate() {
30
+ return this._imagesByDay[this.selectedIndex].referenceDate
31
+ }
32
+
33
+ get imageUrls() {
34
+ return this._imagesByDay[this.selectedIndex].urls
35
+ }
36
+ }
@@ -0,0 +1,14 @@
1
+ export class SampleRaster {
2
+ constructor(data) {
3
+ this._data = data
4
+ }
5
+
6
+ getPixel(x, y) {
7
+ const pixel = this._data[x][y]
8
+ if (pixel !== ' ') {
9
+ const value = Number.parseInt(pixel)
10
+ return [value, value, value, 255]
11
+ } else return [0, 0, 0, 0]
12
+ }
13
+ }
14
+
@@ -0,0 +1,5 @@
1
+ export { BuildingMap } from './BuildingMap'
2
+ export { BuildingPickerResourceProvider } from './BuildingPickerResourceProvider'
3
+ export { CanvasRaster } from './CanvasRaster'
4
+ export { DayOfYearSelector } from './DayOfYearSelector'
5
+ export { SampleRaster } from './SampleRaster'
@@ -0,0 +1,4 @@
1
+ export * from './apartmentChooser'
2
+ export * from './buildingPicker'
3
+ export * from './shared'
4
+ // export * from './virtualTour'
@@ -0,0 +1,52 @@
1
+ export class BatchLoadTracker {
2
+ constructor(numParts) {
3
+ this._numParts = numParts
4
+ this._loadedCount = 0
5
+ this._isError = false
6
+ this._finishedAction = () => {}
7
+ this._errorAction = () => {}
8
+ this._loadProgressAction = () => {}
9
+ }
10
+
11
+ onLoadFinished(action) {
12
+ this._finishedAction = action
13
+ return this
14
+ }
15
+
16
+ onLoadError(action) {
17
+ this._errorAction = action
18
+ return this
19
+ }
20
+
21
+ onLoadProgress(action) {
22
+ this._loadProgressAction = action
23
+ return this
24
+ }
25
+
26
+ partLoaded() {
27
+ if (this.isFinished) return
28
+
29
+ this._loadedCount++
30
+ this._loadProgressAction(this.percentLoaded)
31
+ if (this.isFinished) this._finishedAction()
32
+ }
33
+
34
+ errorDetected() {
35
+ if (this._isError) return
36
+
37
+ this._isError = true
38
+ this._errorAction()
39
+ }
40
+
41
+ get isFinished() {
42
+ return this._loadedCount >= this._numParts
43
+ }
44
+
45
+ get isError() {
46
+ return this._isError
47
+ }
48
+
49
+ get percentLoaded() {
50
+ return Math.round((this._loadedCount * 100) / this._numParts)
51
+ }
52
+ }
@@ -0,0 +1,65 @@
1
+ const defaultLabels = {
2
+ // virtual tour default labels
3
+ interior: 'Interiør',
4
+ 'see-a-selection-of-the-options-in-the-project':
5
+ 'Se et utvalg av tilvalgsmulighetene i prosjektet.',
6
+ 'floor-plan': 'Planløsning',
7
+ 'all-illustrations-are-indicative-deviations-may-occur':
8
+ { nb: 'Alle illustrasjoner er veiledende. Avvik kan forekomme.', en: 'All illustrations are indicative. Discrepancies may exist.' },
9
+ 'read-more-here': 'Les mer her',
10
+ 'i-understand': { nb: 'Jeg forstår', en: "I understand" },
11
+ share: 'Share',
12
+ 'share-to-facebook': 'Share to Facebook',
13
+ 'share-to-linkedin': 'Share to Linkedin',
14
+ 'share-to-twitter': 'Share to Twitter',
15
+ 'share-via-email': 'Share via Email',
16
+ 'copy-link': 'Copy link',
17
+ 'virtual-view': 'Virtuell Visning',
18
+ 'slide-show': 'Slide Show',
19
+ // building chooser default labels
20
+ room: 'Room',
21
+ floor: 'Floor',
22
+ 'see-apartments': 'See apartments',
23
+ // apartment chooser default labels
24
+ 'see-apartment': 'See apartment',
25
+
26
+ "click-and-drag-to-look-around": { en: "Click and drag to look around", nb: "Klikk og dra for å se deg rundt" },
27
+ "click-on-the-cricles-to-move-around": { en: "Click on the circles to move around", nb: "Klikk på sirkelene for å gå rundt" },
28
+ "use-the-mouse-wheel-to-zoom": { en: "Use the mouse wheel to zoom", nb: "Bruk mushjulet for å zoome" },
29
+ "you-can-also-use-the-arrow-keys-to-move-around": { en: "You can also use the arrow keys to move around", nb: "Du kan også bruke pilene på tastaturet for å gå rundt" },
30
+ "tap-and-drag-to-look-around": { en: "Tap and drag to look around", nb: "Trykk og dra for å se deg rundt" },
31
+ "tap-on-the-circles-to-move-around": { en: "Tap on the circles to move around", nb: "Trykk på sirkelene for å gå rundt" },
32
+ "use-two-fingers-to-zoom": { en: "Use two fingers to zoom", nb: "Bruk to fingre for å zoome" },
33
+ "dont-show-again": { en: "Don't Show Again", nb: "Ikke vis igjen" }
34
+
35
+
36
+ }
37
+
38
+ export class I18N {
39
+ constructor(labels, language) {
40
+ this._labels = { ...defaultLabels, ...(labels || {}) }
41
+ this._language = language || 'en'
42
+ }
43
+
44
+ getLabel(key) {
45
+ if (key in this._labels) {
46
+ return this.get(this._labels[key])
47
+ }
48
+ return key
49
+ }
50
+
51
+ get(i18nObject) {
52
+ if (typeof i18nObject === 'string') {
53
+ return i18nObject
54
+ } else if (this._language in i18nObject && i18nObject[this._language]) {
55
+ return i18nObject[this._language]
56
+ } else {
57
+ for (const fallbackLocale in i18nObject) {
58
+ if (i18nObject[fallbackLocale]) {
59
+ return i18nObject[fallbackLocale]
60
+ }
61
+ }
62
+ }
63
+ return ''
64
+ }
65
+ }
@@ -0,0 +1,33 @@
1
+ import axios from 'axios'
2
+
3
+ export class ResourceLoader {
4
+ async loadJson(url) {
5
+ return (await axios.get(url)).data
6
+ }
7
+
8
+ async loadImage(url) {
9
+ return new Promise((resolve, reject) => {
10
+ const tmpImage = new Image()
11
+ tmpImage.crossOrigin = 'anonymous'
12
+ tmpImage.onload = () => {
13
+ resolve(tmpImage)
14
+ }
15
+ tmpImage.onerror = reject
16
+ tmpImage.src = url
17
+ })
18
+ }
19
+
20
+ async loadImageData(url) {
21
+ const image = await this.loadImage(url)
22
+ const canvas = document.createElement('canvas')
23
+ try {
24
+ const ctx = canvas.getContext('2d')
25
+ canvas.width = image.width
26
+ canvas.height = image.height
27
+ ctx.drawImage(image, 0, 0)
28
+ return canvas.toDataURL('image/png')
29
+ } finally {
30
+ canvas.remove()
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ export { ResourceLoader } from './ResourceLoader'
2
+ export { I18N } from './I18N'
3
+ export { BatchLoadTracker } from './BatchLoadTracker'
@@ -0,0 +1,42 @@
1
+ function padded(num) {
2
+ return ('0' + num).slice(-2)
3
+ }
4
+
5
+ // Makes a string in the format of YYYYMMDD HHMMSS
6
+ function makeTimestampString() {
7
+ const now = new Date()
8
+ return [
9
+ now.getFullYear().toString(),
10
+ padded(now.getMonth() + 1),
11
+ padded(now.getDate()),
12
+ ' ',
13
+ padded(now.getHours()),
14
+ padded(now.getMinutes()),
15
+ padded(now.getSeconds()),
16
+ ].join('')
17
+ }
18
+
19
+ function makeDefaultFilename() {
20
+ return 'Visuado-Snapshot-' + makeTimestampString()
21
+ }
22
+
23
+ export class CameraSnapshot {
24
+ constructor(data, cameraParams) {
25
+ this.data = data
26
+ this.cameraParams = cameraParams
27
+ }
28
+
29
+ download(filename = null) {
30
+ filename = filename || makeDefaultFilename()
31
+ const link = document.createElement('a')
32
+ if (typeof link.download === 'string') {
33
+ document.body.appendChild(link) //Firefox requires the link to be in the body
34
+ link.download = filename
35
+ link.href = this.data
36
+ link.click()
37
+ document.body.removeChild(link)
38
+ } else {
39
+ location.replace(uri)
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,69 @@
1
+ export class FullscreenModel {
2
+ constructor(document, elemId) {
3
+ this._doc = document
4
+ this._elemId = elemId
5
+ this._state = { isActive: false }
6
+ }
7
+
8
+ get isActive() {
9
+ return this._state.isActive
10
+ }
11
+
12
+ setup() {
13
+ const events = [
14
+ 'fullscreenchange',
15
+ 'webkitfullscreenchange',
16
+ 'mozfullscreenchange',
17
+ 'msfullscreenchange',
18
+ ]
19
+ const element = this._getElement()
20
+ events.forEach((event) => {
21
+ element.addEventListener(event, this._toggle.bind(this), false)
22
+ })
23
+ }
24
+
25
+ toggle() {
26
+ if (this.isActive) this._exit()
27
+ else this._enter()
28
+ }
29
+
30
+ _enter() {
31
+
32
+ const elem = this._getElement()
33
+ const method =
34
+ elem.requestFullscreen ||
35
+ elem.webkitRequestFullscreen ||
36
+ elem.mozRequestFullscreen ||
37
+ elem.msRequestFullscreen
38
+
39
+ if (method) {
40
+ method.apply(elem)
41
+ }
42
+
43
+ }
44
+
45
+ _exit() {
46
+ const method =
47
+ this._doc.exitFullscreen ||
48
+ this._doc.webkitExitFullscreen ||
49
+ this._doc.mozExitFullscreen ||
50
+ this._doc.document.msExitFullscreen
51
+ if (method) {
52
+ method.apply(document)
53
+ }
54
+ }
55
+
56
+ _getElement() {
57
+ return this._doc.getElementById(this._elemId)
58
+ }
59
+
60
+ _toggle() {
61
+ const activeState = !!(
62
+ this._doc.fullscreenElement ||
63
+ this._doc.webkitFullscreenElement ||
64
+ this._doc.mozFullscreenElement ||
65
+ this._doc.msFullscreenElement
66
+ )
67
+ this._state.isActive = activeState
68
+ }
69
+ }
@@ -0,0 +1,4 @@
1
+ <svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M8.98034 14.7993L1.54055 10.3376L8.98034 5.87599L16.4201 10.3376L8.98034 14.7993Z" fill="white" stroke="black" stroke-width="1.5" stroke-linejoin="round"/>
3
+ <path d="M8.98034 10.3472L1.54055 5.8855L8.98034 1.42384L16.4201 5.8855L8.98034 10.3472Z" fill="white" stroke="#999999" stroke-width="1.5" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="19" height="16" viewBox="0 0 19 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M9.76135 14.7993L2.32155 10.3376L9.76135 5.87599L17.2011 10.3376L9.76135 14.7993Z" fill="white" stroke="#999999" stroke-width="1.5" stroke-linejoin="round"/>
3
+ <path d="M9.76135 10.3472L2.32155 5.8855L9.76135 1.42384L17.2011 5.8855L9.76135 10.3472Z" fill="white" stroke="black" stroke-width="1.5" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,80 @@
1
+ import { ProjectFiles } from './ApartmentFiles'
2
+
3
+ type CameraConfig = object
4
+
5
+ type TimeOfDay = {
6
+ hours: number
7
+ minutes: number
8
+ }
9
+
10
+ type ApartmentConfigJson = {
11
+ cameras: CameraConfig[]
12
+ timeInHours?: number
13
+ }
14
+
15
+ type ThumbnailsConfigJson = {
16
+ cameras: CameraConfig[]
17
+ }
18
+
19
+ const DEFAULT_APARTMENT_CONFIG: ApartmentConfigJson = { cameras: [] }
20
+ const DEFAULT_THUMBNAILS_CONFIG: ThumbnailsConfigJson = { cameras: [] }
21
+
22
+ export class ApartmentConfig {
23
+ static async load(files: ProjectFiles) {
24
+ const [apartmentJson, thumbnailsJson] = await Promise.all([
25
+ this.loadApartmentJson(files),
26
+ this.loadThumbnailsJson(files),
27
+ ])
28
+ return new ApartmentConfig(apartmentJson, thumbnailsJson)
29
+ }
30
+
31
+ constructor(
32
+ private readonly apartmentJson: ApartmentConfigJson,
33
+ private readonly thumbnailsJson: ThumbnailsConfigJson
34
+ ) {}
35
+
36
+ get timeOfDay(): TimeOfDay | undefined {
37
+ return this.parseTimeOfDay(this.apartmentJson.timeInHours)
38
+ }
39
+
40
+ get cameras(): CameraConfig[] {
41
+ return this.apartmentJson.cameras
42
+ }
43
+
44
+ get thumbnailCameras(): CameraConfig[] {
45
+ return this.thumbnailsJson.cameras
46
+ }
47
+
48
+ private parseTimeOfDay(floatValue?: number): TimeOfDay | undefined {
49
+ if (!floatValue) return undefined
50
+
51
+ const hours = Math.floor(floatValue)
52
+ const minutes = Math.floor((hours - floatValue) * 60)
53
+ return { hours, minutes }
54
+ }
55
+
56
+ private static loadApartmentJson(files: ProjectFiles) {
57
+ return this.loadJson<ApartmentConfigJson>(
58
+ files,
59
+ 'apartment.json',
60
+ DEFAULT_APARTMENT_CONFIG
61
+ )
62
+ }
63
+
64
+ private static async loadThumbnailsJson(files: ProjectFiles) {
65
+ return this.loadJson<ThumbnailsConfigJson>(
66
+ files,
67
+ 'thumbs.json',
68
+ DEFAULT_THUMBNAILS_CONFIG
69
+ )
70
+ }
71
+
72
+ private static async loadJson<T>(
73
+ files: ProjectFiles,
74
+ filename: string,
75
+ defaultValue: T
76
+ ) {
77
+ const jsonFile = files.makeFile(filename)
78
+ return (await jsonFile.readJson<T>()) ?? defaultValue
79
+ }
80
+ }
@@ -0,0 +1,8 @@
1
+ export interface ProjectFile {
2
+ readJson<T>(): Promise<T | undefined>
3
+ toPath(): string
4
+ }
5
+
6
+ export interface ProjectFiles {
7
+ makeFile(...parts: string[]): ProjectFile
8
+ }