@c4h/chuci 0.1.0 → 0.2.1
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/CHANGELOG.md +32 -32
- package/LICENSE +20 -20
- package/README.ja.md +143 -143
- package/README.md +224 -224
- package/dist/chuci.js +9068 -6596
- package/dist/chuci.umd.js +165 -166
- package/dist/index.d.ts +1 -0
- package/package.json +36 -33
- package/src/components/swiper/cc-swiper-slide.ts +49 -49
- package/src/components/swiper/cc-swiper-styles.ts +28 -28
- package/src/components/swiper/cc-swiper.ts +379 -361
- package/src/components/swiper/swiper-styles.css +4 -4
- package/src/components/viewer/cc-viewer-3dmodel.ts +491 -491
- package/src/components/viewer/cc-viewer-base.ts +278 -278
- package/src/components/viewer/cc-viewer-gaussian.ts +380 -380
- package/src/components/viewer/cc-viewer-image.ts +189 -189
- package/src/components/viewer/cc-viewer-panorama.ts +85 -85
- package/src/components/viewer/cc-viewer-styles.ts +55 -55
- package/src/components/viewer/cc-viewer-video.ts +109 -109
- package/src/components/viewer/cc-viewer-youtube.ts +75 -75
- package/src/components/viewer/cc-viewer.ts +290 -290
- package/src/index.ts +24 -24
- package/src/types/css-modules.d.ts +1 -1
- package/src/types/global.d.ts +10 -10
- package/src/utils/base-element.ts +76 -76
- package/dist/assets/azumaya_panorama1.png +0 -0
- package/dist/chuci.cjs +0 -4483
- package/dist/index-8VMexD2a.cjs +0 -255
- package/dist/index-kvsisbKS.js +0 -2125
- package/dist/index.html +0 -241
- package/dist/test-image.html +0 -63
|
@@ -1,291 +1,291 @@
|
|
|
1
|
-
import { ChuciElement } from '@/utils/base-element'
|
|
2
|
-
import './cc-viewer-image'
|
|
3
|
-
import './cc-viewer-panorama'
|
|
4
|
-
import './cc-viewer-youtube'
|
|
5
|
-
import './cc-viewer-video'
|
|
6
|
-
import './cc-viewer-3dmodel'
|
|
7
|
-
import './cc-viewer-gaussian'
|
|
8
|
-
|
|
9
|
-
interface HashKeyTag {
|
|
10
|
-
[index: string]: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const typeHashes = {
|
|
14
|
-
image: 'cc-viewer-image',
|
|
15
|
-
panorama: 'cc-viewer-panorama',
|
|
16
|
-
youtube: 'cc-viewer-youtube',
|
|
17
|
-
video: 'cc-viewer-video',
|
|
18
|
-
'3dmodel': 'cc-viewer-3dmodel',
|
|
19
|
-
gaussian: 'cc-viewer-gaussian'
|
|
20
|
-
} as HashKeyTag
|
|
21
|
-
|
|
22
|
-
export class CcViewer extends ChuciElement {
|
|
23
|
-
// Swiper instance from cc-swiper component, no TypeScript types available
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
-
private swiper: any
|
|
26
|
-
private currentSlideIndex = 0
|
|
27
|
-
private currentType = ''
|
|
28
|
-
private boundHandleNavigatePrev?: (e: Event) => void
|
|
29
|
-
private boundHandleNavigateNext?: (e: Event) => void
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
-
open(imgUrl: string, type: string, attributes?: Record<string, any>) {
|
|
34
|
-
const previousType = this.currentType
|
|
35
|
-
this.currentType = type
|
|
36
|
-
|
|
37
|
-
// Close previous viewer if type changed
|
|
38
|
-
if (previousType && previousType !== type) {
|
|
39
|
-
const previousTag = typeHashes[previousType]
|
|
40
|
-
const previousHandler = this.query(previousTag)
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
-
if (previousHandler && (previousHandler as any).close) {
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
-
(previousHandler as any).close()
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Re-render if type changed
|
|
49
|
-
if (previousType !== type) {
|
|
50
|
-
this.render()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Wait for render to complete
|
|
54
|
-
setTimeout(() => {
|
|
55
|
-
const targetTag = typeHashes[type]
|
|
56
|
-
const handler = this.query(targetTag)
|
|
57
|
-
|
|
58
|
-
// Pass attributes to the viewer if available
|
|
59
|
-
if (handler && attributes) {
|
|
60
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
61
|
-
// Convert camelCase to kebab-case for attributes
|
|
62
|
-
const attrName = key.replace(/([A-Z])/g, '-$1').toLowerCase()
|
|
63
|
-
if (typeof value === 'boolean') {
|
|
64
|
-
if (value) {
|
|
65
|
-
handler.setAttribute(attrName, '')
|
|
66
|
-
} else {
|
|
67
|
-
handler.removeAttribute(attrName)
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
handler.setAttribute(attrName, String(value))
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Update navigation button visibility
|
|
76
|
-
this.updateNavigationButtons()
|
|
77
|
-
|
|
78
|
-
if (handler) {
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
-
;(handler as any).open(imgUrl)
|
|
81
|
-
}
|
|
82
|
-
}, 0)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
protected firstUpdated() {
|
|
86
|
-
// Dispatch load event when the component is ready
|
|
87
|
-
this.dispatch('load')
|
|
88
|
-
|
|
89
|
-
// Remove existing listeners if any
|
|
90
|
-
if (this.boundHandleNavigatePrev) {
|
|
91
|
-
this.removeEventListener('navigate-prev', this.boundHandleNavigatePrev)
|
|
92
|
-
}
|
|
93
|
-
if (this.boundHandleNavigateNext) {
|
|
94
|
-
this.removeEventListener('navigate-next', this.boundHandleNavigateNext)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Create bound functions once
|
|
98
|
-
this.boundHandleNavigatePrev = this.handleNavigatePrev.bind(this)
|
|
99
|
-
this.boundHandleNavigateNext = this.handleNavigateNext.bind(this)
|
|
100
|
-
|
|
101
|
-
// Listen for navigation events
|
|
102
|
-
this.addEventListener('navigate-prev', this.boundHandleNavigatePrev)
|
|
103
|
-
this.addEventListener('navigate-next', this.boundHandleNavigateNext)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private handleNavigatePrev(_e?: Event) {
|
|
107
|
-
if (!this.swiper) return
|
|
108
|
-
|
|
109
|
-
const totalSlides = this.swiper.slides.length
|
|
110
|
-
if (totalSlides <= 1) return // No navigation for single slide
|
|
111
|
-
|
|
112
|
-
// Check if loop is enabled in swiper
|
|
113
|
-
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
114
|
-
|
|
115
|
-
if (this.currentSlideIndex <= 0) {
|
|
116
|
-
if (hasLoop) {
|
|
117
|
-
this.currentSlideIndex = totalSlides - 1 // Go to last slide
|
|
118
|
-
} else {
|
|
119
|
-
return // Can't go previous
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
this.currentSlideIndex--
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
this.navigateToSlide(this.currentSlideIndex)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private handleNavigateNext(_e?: Event) {
|
|
129
|
-
if (!this.swiper) return
|
|
130
|
-
|
|
131
|
-
const totalSlides = this.swiper.slides.length
|
|
132
|
-
if (totalSlides <= 1) return // No navigation for single slide
|
|
133
|
-
|
|
134
|
-
// Check if loop is enabled in swiper
|
|
135
|
-
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
136
|
-
|
|
137
|
-
if (this.currentSlideIndex >= totalSlides - 1) {
|
|
138
|
-
if (hasLoop) {
|
|
139
|
-
this.currentSlideIndex = 0 // Go to first slide
|
|
140
|
-
} else {
|
|
141
|
-
return // Can't go next
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
this.currentSlideIndex++
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
this.navigateToSlide(this.currentSlideIndex)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private navigateToSlide(index: number) {
|
|
151
|
-
if (!this.swiper || !this.swiper.slides[index]) return
|
|
152
|
-
|
|
153
|
-
// Get new slide info first
|
|
154
|
-
const slide = this.swiper.slides[index]
|
|
155
|
-
const imageUrl = slide.getAttribute('image-url') || ''
|
|
156
|
-
const imageType = slide.getAttribute('image-type') || 'image'
|
|
157
|
-
|
|
158
|
-
// Close current viewer
|
|
159
|
-
const currentTag = typeHashes[this.currentType]
|
|
160
|
-
const currentHandler = this.query(currentTag)
|
|
161
|
-
if (currentHandler) {
|
|
162
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
-
(currentHandler as any).close()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Gather viewer-specific attributes
|
|
167
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
168
|
-
const attributes: Record<string, any> = {}
|
|
169
|
-
if (slide.hasAttribute('fit-to-container')) {
|
|
170
|
-
attributes.fitToContainer = true
|
|
171
|
-
}
|
|
172
|
-
if (slide.hasAttribute('debug-mode')) {
|
|
173
|
-
attributes.debugMode = true
|
|
174
|
-
}
|
|
175
|
-
if (slide.hasAttribute('camera-position')) {
|
|
176
|
-
attributes.cameraPosition = slide.getAttribute('camera-position')
|
|
177
|
-
}
|
|
178
|
-
if (slide.hasAttribute('camera-target')) {
|
|
179
|
-
attributes.cameraTarget = slide.getAttribute('camera-target')
|
|
180
|
-
}
|
|
181
|
-
if (slide.hasAttribute('show-texture')) {
|
|
182
|
-
attributes.showTexture = slide.getAttribute('show-texture') === 'true'
|
|
183
|
-
}
|
|
184
|
-
if (slide.hasAttribute('material-url')) {
|
|
185
|
-
attributes.materialUrl = slide.getAttribute('material-url')
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this.currentSlideIndex = index
|
|
189
|
-
this.open(imageUrl, imageType, attributes)
|
|
190
|
-
|
|
191
|
-
// Update swiper position
|
|
192
|
-
if (this.swiper.slider) {
|
|
193
|
-
this.swiper.slider.slideTo(index)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
private updateNavigationButtons() {
|
|
198
|
-
if (!this.swiper) return
|
|
199
|
-
|
|
200
|
-
const totalSlides = this.swiper.slides.length
|
|
201
|
-
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
202
|
-
|
|
203
|
-
// For single slide, hide both buttons
|
|
204
|
-
if (totalSlides <= 1) {
|
|
205
|
-
this.setNavigationVisibility(false, false)
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// For multiple slides with loop, show both
|
|
210
|
-
if (hasLoop) {
|
|
211
|
-
this.setNavigationVisibility(true, true)
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// For multiple slides without loop, check boundaries
|
|
216
|
-
const showPrev = this.currentSlideIndex > 0
|
|
217
|
-
const showNext = this.currentSlideIndex < totalSlides - 1
|
|
218
|
-
this.setNavigationVisibility(showPrev, showNext)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private setNavigationVisibility(showPrev: boolean, showNext: boolean) {
|
|
222
|
-
// Update all viewer instances
|
|
223
|
-
const viewers = [
|
|
224
|
-
this.query('cc-viewer-image'),
|
|
225
|
-
this.query('cc-viewer-youtube'),
|
|
226
|
-
this.query('cc-viewer-panorama'),
|
|
227
|
-
this.query('cc-viewer-video'),
|
|
228
|
-
this.query('cc-viewer-3dmodel'),
|
|
229
|
-
this.query('cc-viewer-gaussian')
|
|
230
|
-
]
|
|
231
|
-
|
|
232
|
-
viewers.forEach(viewer => {
|
|
233
|
-
if (viewer) {
|
|
234
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
-
const v = viewer as any
|
|
236
|
-
v.showPrevButton = showPrev
|
|
237
|
-
v.showNextButton = showNext
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Public method to set swiper reference
|
|
243
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
-
setSwiper(swiper: any) {
|
|
245
|
-
this.swiper = swiper
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Public method to set current slide index
|
|
249
|
-
setCurrentSlideIndex(index: number) {
|
|
250
|
-
this.currentSlideIndex = index
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
protected render() {
|
|
254
|
-
const styles = this.css`
|
|
255
|
-
:host {
|
|
256
|
-
--cc-viewer-z-index: 1000;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
cc-viewer-panorama, cc-viewer-image, cc-viewer-youtube, cc-viewer-video,
|
|
260
|
-
cc-viewer-3dmodel, cc-viewer-gaussian {
|
|
261
|
-
--cc-viewer-z-index-each: var(--cc-viewer-z-index);
|
|
262
|
-
}
|
|
263
|
-
`
|
|
264
|
-
|
|
265
|
-
// Only render the current viewer type
|
|
266
|
-
let viewerHtml = ''
|
|
267
|
-
if (this.currentType) {
|
|
268
|
-
const tag = typeHashes[this.currentType]
|
|
269
|
-
if (tag) {
|
|
270
|
-
viewerHtml = `<${tag}></${tag}>`
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const html = `
|
|
275
|
-
${styles}
|
|
276
|
-
${viewerHtml}
|
|
277
|
-
`
|
|
278
|
-
|
|
279
|
-
this.updateShadowRoot(html)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (!customElements.get('cc-viewer')) {
|
|
284
|
-
customElements.define('cc-viewer', CcViewer)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
declare global {
|
|
288
|
-
interface HTMLElementTagNameMap {
|
|
289
|
-
'cc-viewer': CcViewer
|
|
290
|
-
}
|
|
1
|
+
import { ChuciElement } from '@/utils/base-element'
|
|
2
|
+
import './cc-viewer-image'
|
|
3
|
+
import './cc-viewer-panorama'
|
|
4
|
+
import './cc-viewer-youtube'
|
|
5
|
+
import './cc-viewer-video'
|
|
6
|
+
import './cc-viewer-3dmodel'
|
|
7
|
+
import './cc-viewer-gaussian'
|
|
8
|
+
|
|
9
|
+
interface HashKeyTag {
|
|
10
|
+
[index: string]: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const typeHashes = {
|
|
14
|
+
image: 'cc-viewer-image',
|
|
15
|
+
panorama: 'cc-viewer-panorama',
|
|
16
|
+
youtube: 'cc-viewer-youtube',
|
|
17
|
+
video: 'cc-viewer-video',
|
|
18
|
+
'3dmodel': 'cc-viewer-3dmodel',
|
|
19
|
+
gaussian: 'cc-viewer-gaussian'
|
|
20
|
+
} as HashKeyTag
|
|
21
|
+
|
|
22
|
+
export class CcViewer extends ChuciElement {
|
|
23
|
+
// Swiper instance from cc-swiper component, no TypeScript types available
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
private swiper: any
|
|
26
|
+
private currentSlideIndex = 0
|
|
27
|
+
private currentType = ''
|
|
28
|
+
private boundHandleNavigatePrev?: (e: Event) => void
|
|
29
|
+
private boundHandleNavigateNext?: (e: Event) => void
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
open(imgUrl: string, type: string, attributes?: Record<string, any>) {
|
|
34
|
+
const previousType = this.currentType
|
|
35
|
+
this.currentType = type
|
|
36
|
+
|
|
37
|
+
// Close previous viewer if type changed
|
|
38
|
+
if (previousType && previousType !== type) {
|
|
39
|
+
const previousTag = typeHashes[previousType]
|
|
40
|
+
const previousHandler = this.query(previousTag)
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
if (previousHandler && (previousHandler as any).close) {
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
(previousHandler as any).close()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Re-render if type changed
|
|
49
|
+
if (previousType !== type) {
|
|
50
|
+
this.render()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Wait for render to complete
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
const targetTag = typeHashes[type]
|
|
56
|
+
const handler = this.query(targetTag)
|
|
57
|
+
|
|
58
|
+
// Pass attributes to the viewer if available
|
|
59
|
+
if (handler && attributes) {
|
|
60
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
61
|
+
// Convert camelCase to kebab-case for attributes
|
|
62
|
+
const attrName = key.replace(/([A-Z])/g, '-$1').toLowerCase()
|
|
63
|
+
if (typeof value === 'boolean') {
|
|
64
|
+
if (value) {
|
|
65
|
+
handler.setAttribute(attrName, '')
|
|
66
|
+
} else {
|
|
67
|
+
handler.removeAttribute(attrName)
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
handler.setAttribute(attrName, String(value))
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Update navigation button visibility
|
|
76
|
+
this.updateNavigationButtons()
|
|
77
|
+
|
|
78
|
+
if (handler) {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
+
;(handler as any).open(imgUrl)
|
|
81
|
+
}
|
|
82
|
+
}, 0)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected firstUpdated() {
|
|
86
|
+
// Dispatch load event when the component is ready
|
|
87
|
+
this.dispatch('load')
|
|
88
|
+
|
|
89
|
+
// Remove existing listeners if any
|
|
90
|
+
if (this.boundHandleNavigatePrev) {
|
|
91
|
+
this.removeEventListener('navigate-prev', this.boundHandleNavigatePrev)
|
|
92
|
+
}
|
|
93
|
+
if (this.boundHandleNavigateNext) {
|
|
94
|
+
this.removeEventListener('navigate-next', this.boundHandleNavigateNext)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Create bound functions once
|
|
98
|
+
this.boundHandleNavigatePrev = this.handleNavigatePrev.bind(this)
|
|
99
|
+
this.boundHandleNavigateNext = this.handleNavigateNext.bind(this)
|
|
100
|
+
|
|
101
|
+
// Listen for navigation events
|
|
102
|
+
this.addEventListener('navigate-prev', this.boundHandleNavigatePrev)
|
|
103
|
+
this.addEventListener('navigate-next', this.boundHandleNavigateNext)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private handleNavigatePrev(_e?: Event) {
|
|
107
|
+
if (!this.swiper) return
|
|
108
|
+
|
|
109
|
+
const totalSlides = this.swiper.slides.length
|
|
110
|
+
if (totalSlides <= 1) return // No navigation for single slide
|
|
111
|
+
|
|
112
|
+
// Check if loop is enabled in swiper
|
|
113
|
+
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
114
|
+
|
|
115
|
+
if (this.currentSlideIndex <= 0) {
|
|
116
|
+
if (hasLoop) {
|
|
117
|
+
this.currentSlideIndex = totalSlides - 1 // Go to last slide
|
|
118
|
+
} else {
|
|
119
|
+
return // Can't go previous
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
this.currentSlideIndex--
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.navigateToSlide(this.currentSlideIndex)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private handleNavigateNext(_e?: Event) {
|
|
129
|
+
if (!this.swiper) return
|
|
130
|
+
|
|
131
|
+
const totalSlides = this.swiper.slides.length
|
|
132
|
+
if (totalSlides <= 1) return // No navigation for single slide
|
|
133
|
+
|
|
134
|
+
// Check if loop is enabled in swiper
|
|
135
|
+
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
136
|
+
|
|
137
|
+
if (this.currentSlideIndex >= totalSlides - 1) {
|
|
138
|
+
if (hasLoop) {
|
|
139
|
+
this.currentSlideIndex = 0 // Go to first slide
|
|
140
|
+
} else {
|
|
141
|
+
return // Can't go next
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
this.currentSlideIndex++
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.navigateToSlide(this.currentSlideIndex)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private navigateToSlide(index: number) {
|
|
151
|
+
if (!this.swiper || !this.swiper.slides[index]) return
|
|
152
|
+
|
|
153
|
+
// Get new slide info first
|
|
154
|
+
const slide = this.swiper.slides[index]
|
|
155
|
+
const imageUrl = slide.getAttribute('image-url') || ''
|
|
156
|
+
const imageType = slide.getAttribute('image-type') || 'image'
|
|
157
|
+
|
|
158
|
+
// Close current viewer
|
|
159
|
+
const currentTag = typeHashes[this.currentType]
|
|
160
|
+
const currentHandler = this.query(currentTag)
|
|
161
|
+
if (currentHandler) {
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
(currentHandler as any).close()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Gather viewer-specific attributes
|
|
167
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
168
|
+
const attributes: Record<string, any> = {}
|
|
169
|
+
if (slide.hasAttribute('fit-to-container')) {
|
|
170
|
+
attributes.fitToContainer = true
|
|
171
|
+
}
|
|
172
|
+
if (slide.hasAttribute('debug-mode')) {
|
|
173
|
+
attributes.debugMode = true
|
|
174
|
+
}
|
|
175
|
+
if (slide.hasAttribute('camera-position')) {
|
|
176
|
+
attributes.cameraPosition = slide.getAttribute('camera-position')
|
|
177
|
+
}
|
|
178
|
+
if (slide.hasAttribute('camera-target')) {
|
|
179
|
+
attributes.cameraTarget = slide.getAttribute('camera-target')
|
|
180
|
+
}
|
|
181
|
+
if (slide.hasAttribute('show-texture')) {
|
|
182
|
+
attributes.showTexture = slide.getAttribute('show-texture') === 'true'
|
|
183
|
+
}
|
|
184
|
+
if (slide.hasAttribute('material-url')) {
|
|
185
|
+
attributes.materialUrl = slide.getAttribute('material-url')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.currentSlideIndex = index
|
|
189
|
+
this.open(imageUrl, imageType, attributes)
|
|
190
|
+
|
|
191
|
+
// Update swiper position
|
|
192
|
+
if (this.swiper.slider) {
|
|
193
|
+
this.swiper.slider.slideTo(index)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private updateNavigationButtons() {
|
|
198
|
+
if (!this.swiper) return
|
|
199
|
+
|
|
200
|
+
const totalSlides = this.swiper.slides.length
|
|
201
|
+
const hasLoop = this.swiper.slider?.params?.loop === true
|
|
202
|
+
|
|
203
|
+
// For single slide, hide both buttons
|
|
204
|
+
if (totalSlides <= 1) {
|
|
205
|
+
this.setNavigationVisibility(false, false)
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// For multiple slides with loop, show both
|
|
210
|
+
if (hasLoop) {
|
|
211
|
+
this.setNavigationVisibility(true, true)
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// For multiple slides without loop, check boundaries
|
|
216
|
+
const showPrev = this.currentSlideIndex > 0
|
|
217
|
+
const showNext = this.currentSlideIndex < totalSlides - 1
|
|
218
|
+
this.setNavigationVisibility(showPrev, showNext)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private setNavigationVisibility(showPrev: boolean, showNext: boolean) {
|
|
222
|
+
// Update all viewer instances
|
|
223
|
+
const viewers = [
|
|
224
|
+
this.query('cc-viewer-image'),
|
|
225
|
+
this.query('cc-viewer-youtube'),
|
|
226
|
+
this.query('cc-viewer-panorama'),
|
|
227
|
+
this.query('cc-viewer-video'),
|
|
228
|
+
this.query('cc-viewer-3dmodel'),
|
|
229
|
+
this.query('cc-viewer-gaussian')
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
viewers.forEach(viewer => {
|
|
233
|
+
if (viewer) {
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
+
const v = viewer as any
|
|
236
|
+
v.showPrevButton = showPrev
|
|
237
|
+
v.showNextButton = showNext
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Public method to set swiper reference
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
+
setSwiper(swiper: any) {
|
|
245
|
+
this.swiper = swiper
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Public method to set current slide index
|
|
249
|
+
setCurrentSlideIndex(index: number) {
|
|
250
|
+
this.currentSlideIndex = index
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
protected render() {
|
|
254
|
+
const styles = this.css`
|
|
255
|
+
:host {
|
|
256
|
+
--cc-viewer-z-index: 1000;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
cc-viewer-panorama, cc-viewer-image, cc-viewer-youtube, cc-viewer-video,
|
|
260
|
+
cc-viewer-3dmodel, cc-viewer-gaussian {
|
|
261
|
+
--cc-viewer-z-index-each: var(--cc-viewer-z-index);
|
|
262
|
+
}
|
|
263
|
+
`
|
|
264
|
+
|
|
265
|
+
// Only render the current viewer type
|
|
266
|
+
let viewerHtml = ''
|
|
267
|
+
if (this.currentType) {
|
|
268
|
+
const tag = typeHashes[this.currentType]
|
|
269
|
+
if (tag) {
|
|
270
|
+
viewerHtml = `<${tag}></${tag}>`
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const html = `
|
|
275
|
+
${styles}
|
|
276
|
+
${viewerHtml}
|
|
277
|
+
`
|
|
278
|
+
|
|
279
|
+
this.updateShadowRoot(html)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (!customElements.get('cc-viewer')) {
|
|
284
|
+
customElements.define('cc-viewer', CcViewer)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
declare global {
|
|
288
|
+
interface HTMLElementTagNameMap {
|
|
289
|
+
'cc-viewer': CcViewer
|
|
290
|
+
}
|
|
291
291
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
// Export all components
|
|
2
|
-
export * from './components/swiper/cc-swiper'
|
|
3
|
-
export * from './components/swiper/cc-swiper-slide'
|
|
4
|
-
export * from './components/viewer/cc-viewer'
|
|
5
|
-
export * from './components/viewer/cc-viewer-base'
|
|
6
|
-
export * from './components/viewer/cc-viewer-image'
|
|
7
|
-
export * from './components/viewer/cc-viewer-panorama'
|
|
8
|
-
export * from './components/viewer/cc-viewer-youtube'
|
|
9
|
-
export * from './components/viewer/cc-viewer-video'
|
|
10
|
-
export * from './components/viewer/cc-viewer-3dmodel'
|
|
11
|
-
export * from './components/viewer/cc-viewer-gaussian'
|
|
12
|
-
|
|
13
|
-
// Export utilities
|
|
14
|
-
export * from './utils/base-element'
|
|
15
|
-
|
|
16
|
-
// Auto-register components when imported
|
|
17
|
-
import './components/swiper/cc-swiper'
|
|
18
|
-
import './components/swiper/cc-swiper-slide'
|
|
19
|
-
import './components/viewer/cc-viewer'
|
|
20
|
-
import './components/viewer/cc-viewer-image'
|
|
21
|
-
import './components/viewer/cc-viewer-panorama'
|
|
22
|
-
import './components/viewer/cc-viewer-youtube'
|
|
23
|
-
import './components/viewer/cc-viewer-video'
|
|
24
|
-
import './components/viewer/cc-viewer-3dmodel'
|
|
1
|
+
// Export all components
|
|
2
|
+
export * from './components/swiper/cc-swiper'
|
|
3
|
+
export * from './components/swiper/cc-swiper-slide'
|
|
4
|
+
export * from './components/viewer/cc-viewer'
|
|
5
|
+
export * from './components/viewer/cc-viewer-base'
|
|
6
|
+
export * from './components/viewer/cc-viewer-image'
|
|
7
|
+
export * from './components/viewer/cc-viewer-panorama'
|
|
8
|
+
export * from './components/viewer/cc-viewer-youtube'
|
|
9
|
+
export * from './components/viewer/cc-viewer-video'
|
|
10
|
+
export * from './components/viewer/cc-viewer-3dmodel'
|
|
11
|
+
export * from './components/viewer/cc-viewer-gaussian'
|
|
12
|
+
|
|
13
|
+
// Export utilities
|
|
14
|
+
export * from './utils/base-element'
|
|
15
|
+
|
|
16
|
+
// Auto-register components when imported
|
|
17
|
+
import './components/swiper/cc-swiper'
|
|
18
|
+
import './components/swiper/cc-swiper-slide'
|
|
19
|
+
import './components/viewer/cc-viewer'
|
|
20
|
+
import './components/viewer/cc-viewer-image'
|
|
21
|
+
import './components/viewer/cc-viewer-panorama'
|
|
22
|
+
import './components/viewer/cc-viewer-youtube'
|
|
23
|
+
import './components/viewer/cc-viewer-video'
|
|
24
|
+
import './components/viewer/cc-viewer-3dmodel'
|
|
25
25
|
import './components/viewer/cc-viewer-gaussian'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
declare module "*.css?inline" { const content: string; export default content; }
|
|
1
|
+
declare module "*.css?inline" { const content: string; export default content; }
|
package/src/types/global.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// Global type declarations for Chuci
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
interface Window {
|
|
5
|
-
// gsplat.js library global - external library without TypeScript types
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
-
gsplat?: any;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
1
|
+
// Global type declarations for Chuci
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
// gsplat.js library global - external library without TypeScript types
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
gsplat?: any;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
11
|
export {}
|