Galaxy Z Flip7

Galaxy Z Flip7

Save up to $600 instant trade-in creditθ or $200 off without trade-in.N

Galaxy Z Flip7 in Blue Shadow is on an angle and slightly unfolded showing the cover screen. Galaxy AI.

Pocket-perfect AI

A beam of light creates the outline of an unfolded Galaxy Z Flip7. The device folds to show the cover screen. As the device rotates, the overall screen size increases.

Introducing our thinnest and most advanced Galaxy Z Flip ever, with unparalleled performance that seamlessly fits your lifestyle and your pocket. The expanded Cover Screen is show-stopping from edge to edge, and it's all housed in durable body that's slimmer both folded and unfolded.

Experience the all-new Flip
  • Perfectly pocket-sized smartphone

    Galaxy Z Flip7

    4.1"

    Galaxy Z Flip7 is seen folded from the cover screen. It rotates to show its slim and sleek side profile.

  • Redesigned, stronger FlexHinge

  • Hands-free, share-worthy selfies

    50 MP

    The cover screen of Galaxy Z Flip7 is seen expanding to become wider. Pictures can be taken and viewed from the cover screen in your hand.

  • Galaxy AI in the palm of your hand

    Now Brief's Weekend brief can be seen on the cover screen of Galaxy Z Flip7. The user can scroll through the full Weekend brief on the cover screen to see today's workout record, the latest weather, photo memories and more.

  • Powerful battery for long-lasting use,,

    • Battery capacity

      4300 mAh

    • Watch videos up to

      31 hrs

    A video that is over 3 hours and 15 minutes is being watched on the main screen of Galaxy Z Flip7 thanks to the long battery life.

Samsung products are rated #1 in Design

Experience the fun and pocketability of Galaxy Z Flip7 and see why Samsung is rated #1 in Design by the American Customer Satisfaction Index (ACSI®).

Learn more

Test drive Galaxy AI on your phone

Scan the QR code to experience the wonder of Galaxy AI on your phone, like getting helpful updates from Now Brief and handling multiple tasks with a single ask. Learn more

Try Galaxy QR code.

Personal training, on us

Get 6 months of trainer-led workouts by iFIT on Samsung Health with new qualifying Galaxy Z Flip7.

Ultra sleek.
Ultra pocketable.

The redesigned Cover Screen on Galaxy Z Flip7 features our slimmest bezel yet, enabling you to do more from FlexWindow than ever before. The stunning Main Screen now features an undisrupted viewing experience that's a sight to behold.

Galaxy Z Flip7 is seen being held. The cover screen goes from dark to bright.

Upgraded to flip without fear

See how the design of Galaxy Z Flip7 has advanced

Compare with

Thickness (Unfolded) ,

FlexWindow , , , ,

Bold colors that fit your style

Angle Preset

Two Galaxy Z Flip7 devices in Blue Shadow are seen. One is seen unfolded from the rear and another is seen in FlexMode from the main screen.

Angle Preset

Make every photo a flex

Close up of Galaxy Z Flip7's rear and main screen camera lenses.
Rear Camera
  • 12MP Ultra Wide
  • 50MP Wide 2x Optical Quality Zoom
Main Screen Camera
10MP Main Screen

See camera specs side-by-side

Compare with

Galaxy Z Flip7

50

Flip to your best selfies with a
50MP camera
50MP rear camera. Flip to your best angle. Flip over to a new selfie experience

Captured #withGalaxy Z Flip7
Captured by Galaxy Z Flip7 #withGalaxy
A selfie of a person and their pet is being shot using Galaxy Z Flip7's 50 MP camera and can be viewed on the cover screen. Details and textures of both the person and their pet are accurately captured.
Enjoy richer, more detailed selfies that you can preview and apply custom filters to on FlexWindow.

Finally, a selfie cam worthy of your closeup.

Finally, a selfie cam in all its full-screen glory.

Capture the finer points in every scene with our high-resolution 50MP camera and let our next-gen ProVisual Engine improve clarity to bring out your natural skin tones. You can even use the AI learning-based custom filters to add finishing touches to make your pics uniquely yours.,, The high-resolution 50MP camera on Galaxy Z Flip7 is boosted by ProVisual Engine to deliver rich, beautifully detailed shots with accurate skin tones. Plus, instantly apply custom filters based on AI learning directly from the cover screen to add finishing touches that will make your pics uniquely yours.,, The high-resolution 50MP camera with ProVisual engine on Galaxy Z Flip7 delivers rich, detailed shots with more accurate skin tones–all with the ease of FlexMode. Plus, instantly apply custom filters based on AI learning directly from the cover screen to add finishing touches that will make your pics uniquely yours.,,

Max zoom. Max detail

Get super-clear, share-worthy pics from any distance. Powered by our ProVisual Engine, AI Zoom delivers stunning portraits whether you're taking selfies up-close, Flip in hand, or going hands-free with FlexCam. Once you've snapped your picture, AI will analyze and refine the details to produce crisp photos every time — no need to worry about finding the right distance.

A group selfie is being taken on Galaxy Z Flip7's 50 MP camera and can be previewed on the cover screen. Even when zoomed in by 1.9 times, AI Zoom ensures the details remain clear.
Captured #withGalaxy Z Flip7

Bring details out of the dark

A video is being shot on Galaxy Z Flip7's Wide camera in the style of a camcorder. Thanks to Nightography, details remain sharp and clear even in low light.
Captured #withGalaxy Z Flip7

Capture breathtaking videos even in low light. The high-resolution sensor works together with our advanced ProVisual Engine to deliver richer contrast day or night.,

Galaxy Z Flip7 for business

The features you need to work on-the-go, in a smartphone reimagined to fit small pockets and big business moves.
Galaxy Z Flip7's bright display is powered by Vision Booster which improves screen visibility.

Stylish phone, serious performance

An unfolded Galaxy Z Flip7 is seen horizontally with a scene from a game on the main screen. Color is enhanced by Vision Booster.

The advanced processor on Galaxy Z Flip7 powers everything from the battery to the displays, ensuring that it works at the speed you need it to, whether you're streaming, gaming or editing your latest video.

  • CPU

    9%

    faster processing

  • GPU

    23%

    smoother graphics

  • NPU

    22%

    quicker AI

*Compared to Galaxy Z Flip6

The largest battery on Galaxy Z Flip

Galaxy Z Flip7 is seen unfolded from the main screen with a battery icon on top. The battery size is 4300 milliampere hours.

A 4300mAh battery and mDNIe technology have been optimized so this Flip is ready for hours of uninterrupted entertainment.,,,

See how long the battery on Galaxy Z Flip7 lasts

Compare with

Galaxy Z Flip7

31 ,,

of video playback time

Watch videos up to

more than

Seamless views, inside and out

Discover our smoothest viewing experience on FlexWindow. With up to 120 Hz refresh rates and a peak brightness of 2600 nits, scrolling is easy on your eyes even outdoors. Plus, our improved Vision Booster enhances the color and contrast so you can see every detail clearly.,

Galaxy Z Flip7's bright display is powered by Vision Booster which improves screen visibility.

Storage for everything you need

Keep all your treasured moments on hand with 12GB of memory and a choice of two storage options. Choose up to 256GB of storage if you like to take photos and stream videos. Or, go even bigger with up to 512GB of storage, if you're an avid gamer or download larger apps, to avoid running out of storage space.

Galaxy AI in your pocket

Galaxy AI is designed to push the boundaries of any other smartphone's AI capabilities. Ask for advice in real time, enhance your photos, receive personalized updates from Now Brief and more. Expand your world like never before.

Now Brief Stay ahead of your day
with Now Brief

Now Bar shows Now Brief's Weekend brief alert. Now Bar is seen moving to the bottom of the cover screen of Galaxy Z Flip7. When the notification is pressed, the user can scroll through the full Weekend brief on the cover screen to see today's workout record, the latest weather, photo memories and more.

Receive a personalized summary of your day from Now Brief right from the cover screen. Tailored insights, such as the latest weather and Energy Score, are all available at just a glance.

Now bar Lock into the now

Now Bar, available right from the Cover Screen, gives you direct access to music that's playing, live notifications and more

Various active apps are seen from Now Bar including exercise, music and Now Brief's Weekend brief alert.

Gemini Live Ask Gemini about what you see

Google Gemini Live is active and the user is seeking laundry advice for their dress. Through the camera, the screen shows the care label, highlighting washing symbols.

Speak freely and naturally with Gemini Live to get information in real time. Ask Gemini what symbols mean and get washing instructions for clothes, or get information about a restaurant you saw while walking by. Share your world through the camera to ask for advice or ideas.

Get 6 months of Google AI Pro including 2 TB of storage

Get a 6-month trial on us, with higher access to powerful features in the Gemini app like video generation powered by Veo3, plus 2 TB of secure cloud storage.

Partially folded Galaxy Z Fold7 is seen from the main screen. Google Gemini is active, and it has created video content based on the user's request. Folded Galaxy Z Flip7 is also seen from the cover screen. Google Gemini has been activated and is ready for a conversation.

Your privacy, secured for the era of AI

  • On-device protection

    Our Personal Data Engine gathers and processes your personal data safely. Then it encrypts that data and saves it onto your device with Knox Vault, making it harder for anyone else to gain access.

  • Tailored controls

    Take control over your Galaxy AI. You decide where your data gets processed, either on-device or in the cloud.

  • Connected security

    Knox Matrix Trust Chain technology provides security across your Galaxy ecosystem so you can monitor other devices right from your Galaxy smartphone.

One UI 8.All new for Flip.

Our best, most personalized UI was built from the ground up for both the Main Screen and the Cover Screen. With customizable wallpaper and interactive weather and gallery widgets, your Flip will be uniquely yours.,

Five Galaxy Z Flip7 devices are arranged in various positions with FlexWindow visible. On each of their cover screens, a portrait with Clock Widget, Clock Widget that transforms to Mapview Widgets, Brief Widgets, Video Wallpaper and Cover Home Screen are seen.

Accessories you'll flip for

Flipsuit Case
Ring Case (Silicone)

Why switch to Galaxy Why switch to Galaxy from your iPhone From Android to Galaxy. Get ready to level up your phone

Imagine where our most powerful smartphones can take you. Your iPhone can only take you so far. Your phone can only take you so far. You won't just discover a whole new world, but an entire Galaxy that works smoothly with other Android devices. Make the switch and see how life opens up with Galaxy. It's time for new adventures, new opportunities and a new Galaxy that works just as smoothly with other iOS, Macs and PCs. Life opens up with Galaxy, and we can't wait to show you how. It's time for new adventures, new opportunities and a new Galaxy that works just as smoothly with Android OS and PCs. Life opens up with Galaxy, and we can't wait to show you how.

  • Smart Switch How easy is switching? Smart Switch

    Switching from your current phone is easy. Thanks to Smart Switch, you can transfer your photos, videos, contacts and apps effortlessly and safely.,, Thanks to Smart Switch, you can transfer your photos, videos, contacts and apps effortlessly and safely.,, Switching from your current phone is easy. With Smart Switch, you can transfer your data such as photos, videos, contacts and apps effortlessly and safely.,, Learn more

  • Samsung Wallet How’s Samsung’s AI tech? Samsung Wallet

    Simplify your life with Samsung Wallet — the easy way to make payments, access cards, earn rewards and more. Get Galaxy AI tools you won’t find anywhere else, like Photo Assist for editing the perfect pics with no additional apps. Simplify your life with Samsung Wallet — the easy way to make payments, access cards, earn rewards and more. Learn more Learn more Learn more

  • RCS What about text messaging? RCS

    Rich Communication Services (RCS) lets you send high-quality media, see message receipts and react in real time for enhanced messaging between Android and iOS. Messaging has never been easier, now that iPhone also runs on RCS. React, see read receipts, and send hi-res content seamlessly. Rich Communication Services (RCS) lets you send high-quality media, see message receipts and react in real time for enhanced messaging between Android and iOS. Learn more

Discover the benefits of Galaxy

Connected living starts with Galaxy

Connect your Galaxy Z Flip7 with Galaxy Watch8, Galaxy Buds3 Pro and other Galaxy devices for a seamless, smarter living experience.

Shop Galaxy Watch8

Frequently Asked Questions

Galaxy Z Flip7

Galaxy Z Fold7

Galaxy Z Flip7 FE

Experience Galaxy XR

Galaxy Z Flip7 for business

  1. Compared to previous Galaxy Z Flip models.
  2. Based on Samsung internal lab test conditions with pre-release version of given model connected to earphone via Bluetooth under default settings over LTE. Estimated against battery capacity and measured current over battery power consumption during video playback (video file resolution 720p, saved on device). Actual video playback time may vary by network connection, settings, video file format, screen brightness, battery condition and many other factors.
  3. Actual battery life varies by network environment, features and apps used, frequency of calls and messages, the number of times charged, and many other factors. Estimated against the average usage profile compiled by UX Connect Research. Independently assessed by UX Connect Research between 2025.06.12-2025.06.20 in US with pre-release versions of SM-F766 under default setting using LTE and 5G Sub6 networks. NOT tested under 5G mmWave Network.
  4. Typical value tested under third-party laboratory condition. Typical value is the estimated average value considering the deviation in battery capacity among the battery samples tested under IEC 61960 standard. Rated capacity is 4174 mAh for Galaxy Z Flip7.
  5. Color availability may vary depending on country or carrier.
  6. Exclusively available on Samsung.com.
  7. Armor Aluminum frame does not include volume and side keys, SIM tray or camera lens barrel.
  8. Corning® Gorilla® Glass Victus® 2 is applied to the front and rear of the device.
  9. Thickness measured from top to bottom of the glass when unfolded.
  10. Galaxy Z Flip3 and Galaxy Z Flip4's thickness measured from top to bottom of the glass at the thickest point.
  11. Weight may vary by country or region.
  12. Measured diagonally, Galaxy Z Flip7's Cover Screen size is 4.1” in the full rectangular form; actual viewable area is less due to the rounded corners and camera hole.
  13. Measured diagonally, Galaxy Z Flip3's Cover Screen size is 1.9” in the full rectangle and 1.8” with accounting for the rounded corners; actual viewable area is less due to the rounded corners.
  14. Measured diagonally, Galaxy Z Flip4's Cover Screen size is 1.9” in the full rectangle and 1.8” accounting for the rounded corners; actual viewable area is smaller due to the rounded corners.
  15. Measured diagonally, Galaxy Z Flip5's Cover Screen size is 3.4” in the full rectangular form; actual viewable area is approximately 95% of the full rectangular area due to the rounded corners and lower cutout.
  16. Measured diagonally, Galaxy Z Flip6's Cover Screen size is 3.4” in the full rectangular form; actual viewable area is approximately 95% of the full rectangular area due to the rounded corners and lower cutout.
  17. Results may vary depending on light condition and/or shooting conditions including multiple subjects, being out of focus or moving subjects.
  18. 50MP resolution is available on Galaxy Z Flip7's rear wide camera only.
  19. AI Zoom is applied to distances between digital zoom lengths. Accuracy of results is not guaranteed.
  20. AP performance improvements shown compared to Galaxy Z Flip6. Actual performance will depend on user environment, conditions and pre-installed software and applications.
  21. Galaxy Z Flip7 has a peak brightness of 2600 nits on both the main screen and cover screen. The displays are adaptive, adjusting brightness level automatically based on the environment. In certain illuminance conditions or higher, High Brightness Mode and Vision Booster will be activated.
  22. Storage options and availability may vary by carrier, country or region. Actual storage availability may vary depending on pre-installed software.
  23. Now Brief feature requires Samsung Account login. Service availability may vary by country, language, device model, and apps. Some features may require a network connection. Modes and Routines need to be enabled to use Personal Data Engine for context-based Routines suggestions. User needs to consent to access permissions such as photos, videos, audio files, and calendar events. May not display moments depending upon exposure policy. The description of photos provided by moments may not align with the user's intent. Events schedule notification is supported with calendar apps that utilize Android calendar database and available if Samsung Calendar is installed. Notifications for coupons only available for coupons added to Samsung Wallet with expiration date. To check the Energy Score, the health data tracked from Samsung Galaxy Watch or Samsung Galaxy Ring must be synchronized with the Samsung Health App. The result is for your personal reference only and is not intended for medical purposes.
  24. Availability of functions supported within the apps may vary by country. Some functional widgets may require a network connection and/or Samsung Account login.
  25. Gemini is a trademark of Google LLC. Results for illustrative purposes. Gemini Live feature requires internet connection and Google Account login. Service availability may vary by country, language, device model. Features may differ depending on subscription and results may vary. Compatible with certain features and certain accounts. Currently, you can use a personal Google Account that you manage on your own, or a work or school account for which your administrator has enabled access to Gemini. You must be 13 (or the applicable age in your country) or over to use Gemini with a personal or school Google Account and 18 or over to use Gemini with a work account.
  26. Image shortened and simulated. Results for illustrative purposes and may vary. Check responses for accuracy. Gemini is a trademark of Google LLC. Terms apply. By subscribing, you agree to terms for Google One, AI Credits and offers. Offer ends July 20, 2026. Only available for ages 18+. Unless canceled earlier, Google One will charge $19.99/mo after the trial ends. Cancel anytime. Return of purchased device may result in cancellation of subscription. See full terms at https://one.google.com/offer/terms-and-conditions/samsung-flipfold7-6month-trial
  27. The Personal Data Engine functions under the condition that the Personal Data Intelligence menu is on. Analyzed data will be deleted once the Personal Data Intelligence menu is turned off. Personal Data Engine recognizes select languages and certain accents/dialects, including but not limited to Arabic, (Simplified) Chinese, Dutch, English, French, German, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Romanian, Russian, Spanish, Swedish, Thai, Turkish, and Vietnamese. Personal Data Engine currently analyzes Samsung native applications.
  28. Some functional widgets may require a network connection and/or Samsung Account login. Availability of functions supported within the apps may vary by country.
  29. Weather Wallpaper feature requires network connection to receive the weather data. It can reflect the weather data without network connection once the data is received by the device. Reflection of real-time weather conditions may be delayed as service relies on local weather information updates. Certain indoor, nighttime and low-resolution photos may not be compatible. The accuracy and reliability of the generated output is not guaranteed.
  30. Wired transfers from Android™ devices require the receiving device to have Android™ 5.0 or later and the sending device to have Android™ 5.0 or later. Transfers can be completed without a cable through a wireless connection. For wireless connections, the receiving device must have Android™ 5.0 or later and the sending device must have Android™ 5.0 or later. Open Smart Switch Mobile in “Settings” on the receiving Galaxy device or download the Smart Switch Mobile app from the Galaxy Store. Data, content and apps available for transfer may vary by transmission method.
  31. Wired transfers from iOS require the receiving device to have Android™ 5.0 or later and the sending device to have iOS 5 or later. Transfers can be completed without a cable through a wireless connection or iCloud. For wireless connections, the receiving device must have Android™ 5.0 or later and the sending device must have iOS 12 or later. iCloud transfers require the receiving device to have Android™ 5.0 or later and the sending device to have iOS 5 or later. Open Smart Switch Mobile in “Settings” on the receiving Galaxy device or download the Smart Switch Mobile app from the Galaxy Store. For wireless transfers, download Smart Switch for iOS from the App Store on your iPhone or iPad. Data, content and apps available for transfer may vary by transmission method. Contacts, gallery, videos, calendars and reminders can be transferred wirelessly from an iOS device.
  32. It is recommended to use a wired connection when transferring diverse sets of data at once.
  33. Quick Share feature between Galaxy devices available with the following OS: smartphones and tablets with Android OS version 10.0 (Q) and One UI 2.1 or above, PCs running Windows 10 or later. Requires Samsung Account and Wi-Fi and Bluetooth connection. Quick Share to iOS and Android devices available by sending shared link: individual files shared cannot exceed 10GB (for a total of 10GB per day) and link will expire after two days; requires a Samsung Account and internet connection.
  34. RCS is the latest in messaging. Availability of RCS varies by region and carrier. For cross-OS communication, all members must have RCS enabled. For Android, requires Google Messages. For iPhone, requires iOS 18 or later. Availability of features may vary by market and device. Encryption only available for Android to Android communications. Image quality may vary. Select ”Original quality” under the Media quality choice (HD+) when an image is attached for higher resolution images. Read receipts and typing indicates only supported in 1:1 chats for cross-OS communication. Reactions only available for text messages; photos and videos are not supported for cross-OS communication.
  35. To be eligible for trade-in, your qualifying device must meet all Trade-In Program eligibility requirements. For detailed information, please refer to https://www.samsung.com/us/trade-in/.
  36. Terms and conditions apply. Samsung Care+ coverage, service type and promotion details may vary by country/region and deductible (service fee) may apply. To be eligible for Samsung Care+ promotion benefit, registration may be required. For detailed Samsung Care+ information, please visit https://www.samsung.com/us/support/samsung-care-plus.
  37. Galaxy devices each sold separately.
  38. Measured diagonally, Galaxy Z Flip7's Main Screen size is 6.9” in the full rectangle and 6.8” accounting for the rounded corners; actual viewable area is less due to the rounded corners and camera hole.
  39. Optical quality zoom is enabled by the Adaptive Pixel sensor.
  40. Only compatible with select Visa, Mastercard, American Express, and Discover cards from participating banks and qualifying Samsung devices. Check with your bank/issuer to ensure that your card is compatible; and check the Samsung Wallet FAQ for more information on device compatibility. Digital ID only for select corporate, government and educational institution partners. Student ID only for select education institution partner. Mobile Driver's License only for TSA ID purposes, only for Arizona and Iowa residents at select Arizona and Iowa airports and TSA checkpoints; Mobile Driver's License for TSA ID only and does not replace physical license. Visit the Samsung Wallet FAQ for more information. Digital keys are available for select SmartThings-compatible smart door locks and automobiles. Exact feature availability may vary by model and is subject to change. Movie tickets only available with Atom Tickets currently. Must have the Atom Tickets app and an Atom Tickets account.
  41. IP48: Resists solid particles >1 mm; Tested for submersion in up to 5 feet of fresh water for up to 30 minutes. Rinse residue / dry after wet.
  42. Source: 2025 ACSI® Survey of customers rating their Cell Phone manufacturer. Samsung was rated #1 for Service Experience for Mobile devices. ACSI and its logo are registered trademarks of the American Customer Satisfaction Index. For more about the ACSI, visit www.theacsi.org
  43. 11/3/25-12/31/26 while supplies last, purchase a qualifying product at Samsung.com or the Shop Samsung app and receive a trial of Samsung Health powered by iFit as follows: (a) 30 days with the purchase of: Fold7, Flip7, S25 Ultra, S25+, S25, S25 FE, S25 Edge, A56, A36, A26, or A16, (b) 3 months with the purchase of: Galaxy Buds3 Pro, (c) 6 months with purchase of: Galaxy Watch8, Galaxy Watch8 Classic, Galaxy Watch Ultra. Activation code will be sent via e-mail 14 days after purchase.
\n \n '), e.appendChild(this.els.gestureGuide), this.setGestureGuideFocus() } setGestureGuideFocus() { const t = new il("gesture-guide"); t.on(), this.els.gestureGuide.addEventListener("click", (e => { o(I, !0, 90), this.els.gestureGuide.style.transition = "opacity 0.5s ease", this.els.gestureGuide.style.opacity = 0, t.off(), setTimeout((() => { window.dispatchEvent(new Event("resize")), document.querySelector(".v3d-wrap h1").focus(), this.els.gestureGuide.parentNode.removeChild(this.els.gestureGuide) }), 500) })) } showGestureGuide() { } hideGestureGuide() { } } function sl() { let t = {}; return { get: function (e) { return t[e] }, add: function (e, i) { t[e] = i }, remove: function (e) { delete t[e] }, removeAll: function () { t = {} } } } const rl = "KHR_binary_glTF", al = "KHR_draco_mesh_compression", ol = "KHR_lights_punctual", ll = "KHR_materials_clearcoat", hl = "KHR_materials_ior", cl = "KHR_materials_pbrSpecularGlossiness", dl = "KHR_materials_sheen", ul = "KHR_materials_specular", pl = "KHR_materials_transmission", ml = "KHR_materials_iridescence", fl = "KHR_materials_unlit", gl = "KHR_materials_volume", vl = "KHR_texture_basisu", _l = "KHR_texture_transform", xl = "KHR_mesh_quantization", yl = "KHR_materials_emissive_strength", bl = "EXT_texture_webp", Ml = "EXT_meshopt_compression"; class wl { constructor(t) { this.parser = t, this.name = ol, this.cache = { refs: {}, uses: {} } } _markDefs() { const t = this.parser, e = this.parser.json.nodes || []; for (let i = 0, n = e.length; i = 0) throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures"); return null } return e.loadTextureImage(t, s.source, r) } } class Ol { constructor(t) { this.parser = t, this.name = bl, this.isSupported = null } loadTexture(t) { const e = this.name, i = this.parser, n = i.json, s = n.textures[t]; if (!s.extensions || !s.extensions[e]) return null; const r = s.extensions[e], a = n.images[r.source]; let o = i.textureLoader; if (a.uri) { const t = i.options.manager.getHandler(a.uri); null !== t && (o = t) } return this.detectSupport().then((function (s) { if (s) return i.loadTextureImage(t, r.source, o); if (n.extensionsRequired && n.extensionsRequired.indexOf(e) >= 0) throw new Error("THREE.GLTFLoader: WebP required by asset but unsupported."); return i.loadTexture(t) })) } detectSupport() { return this.isSupported || (this.isSupported = new Promise((function (t) { const e = new Image; e.src = "data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA", e.onload = e.onerror = function () { t(1 === e.height) } }))), this.isSupported } } class Nl { constructor(t) { this.name = Ml, this.parser = t } loadBufferView(t) { const e = this.parser.json, i = e.bufferViews[t]; if (i.extensions && i.extensions[this.name]) { const t = i.extensions[this.name], n = this.parser.getDependency("buffer", t.buffer), s = this.parser.options.meshoptDecoder; if (!s || !s.supported) { if (e.extensionsRequired && e.extensionsRequired.indexOf(this.name) >= 0) throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files"); return null } return Promise.all([n, s.ready]).then((function (e) { const i = t.byteOffset || 0, n = t.byteLength || 0, r = t.count, a = t.byteStride, o = new ArrayBuffer(r * a), l = new Uint8Array(e[0], i, n); return s.decodeGltfBuffer(new Uint8Array(o), r, a, l, t.mode, t.filter), o })) } return null } } const zl = "glTF"; class Fl { constructor(t) { this.name = rl, this.content = null, this.body = null; const e = new DataView(t, 0, 12); if (this.header = { magic: Do.decodeText(new Uint8Array(t.slice(0, 4))), version: e.getUint32(4, !0), length: e.getUint32(8, !0) }, this.header.magic !== zl) throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header."); if (this.header.version ", e).replace("#include ", i).replace("#include ", n).replace("#include ", s).replace("#include ", r) }, Object.defineProperties(this, { specular: { get: function () { return a.specular.value }, set: function (t) { a.specular.value = t } }, specularMap: { get: function () { return a.specularMap.value }, set: function (t) { a.specularMap.value = t, t ? this.defines.USE_SPECULARMAP = "" : delete this.defines.USE_SPECULARMAP } }, glossiness: { get: function () { return a.glossiness.value }, set: function (t) { a.glossiness.value = t } }, glossinessMap: { get: function () { return a.glossinessMap.value }, set: function (t) { a.glossinessMap.value = t, t ? (this.defines.USE_GLOSSINESSMAP = "", this.defines.USE_UV = "") : (delete this.defines.USE_GLOSSINESSMAP, delete this.defines.USE_UV) } } }), delete this.metalness, delete this.roughness, delete this.metalnessMap, delete this.roughnessMap, this.setValues(t) } copy(t) { return super.copy(t), this.specularMap = t.specularMap, this.specular.copy(t.specular), this.glossinessMap = t.glossinessMap, this.glossiness = t.glossiness, delete this.metalness, delete this.roughness, delete this.metalnessMap, delete this.roughnessMap, this } } class Vl { constructor() { this.name = cl, this.specularGlossinessParams = ["color", "map", "lightMap", "lightMapIntensity", "aoMap", "aoMapIntensity", "emissive", "emissiveIntensity", "emissiveMap", "bumpMap", "bumpScale", "normalMap", "normalMapType", "displacementMap", "displacementScale", "displacementBias", "specularMap", "specular", "glossinessMap", "glossiness", "alphaMap", "envMap", "envMapIntensity"] } getMaterialType() { return Bl } extendParams(t, e, i) { const n = e.extensions[this.name]; t.color = new ae(1, 1, 1), t.opacity = 1; const s = []; if (Array.isArray(n.diffuseFactor)) { const e = n.diffuseFactor; t.color.fromArray(e), t.opacity = e[3] } if (void 0 !== n.diffuseTexture && s.push(i.assignTexture(t, "map", n.diffuseTexture, At)), t.emissive = new ae(0, 0, 0), t.glossiness = void 0 !== n.glossinessFactor ? n.glossinessFactor : 1, t.specular = new ae(1, 1, 1), Array.isArray(n.specularFactor) && t.specular.fromArray(n.specularFactor), void 0 !== n.specularGlossinessTexture) { const e = n.specularGlossinessTexture; s.push(i.assignTexture(t, "glossinessMap", e)), s.push(i.assignTexture(t, "specularMap", e, At)) } return Promise.all(s) } createMaterial(t) { const e = new Bl(t); return e.fog = !0, e.color = t.color, e.map = void 0 === t.map ? null : t.map, e.lightMap = null, e.lightMapIntensity = 1, e.aoMap = void 0 === t.aoMap ? null : t.aoMap, e.aoMapIntensity = 1, e.emissive = t.emissive, e.emissiveIntensity = void 0 === t.emissiveIntensity ? 1 : t.emissiveIntensity, e.emissiveMap = void 0 === t.emissiveMap ? null : t.emissiveMap, e.bumpMap = void 0 === t.bumpMap ? null : t.bumpMap, e.bumpScale = 1, e.normalMap = void 0 === t.normalMap ? null : t.normalMap, e.normalMapType = 0, t.normalScale && (e.normalScale = t.normalScale), e.displacementMap = null, e.displacementScale = 1, e.displacementBias = 0, e.specularMap = void 0 === t.specularMap ? null : t.specularMap, e.specular = t.specular, e.glossinessMap = void 0 === t.glossinessMap ? null : t.glossinessMap, e.glossiness = t.glossiness, e.alphaMap = null, e.envMap = void 0 === t.envMap ? null : t.envMap, e.envMapIntensity = 1, e } } class Gl { constructor() { this.name = xl } } class Hl extends Ya { constructor(t, e, i, n) { super(t, e, i, n) } copySampleValue_(t) { const e = this.resultBuffer, i = this.sampleValues, n = this.valueSize, s = t * n * 3 + n; for (let t = 0; t !== n; t++)e[t] = i[s + t]; return e } interpolate_(t, e, i, n) { const s = this.resultBuffer, r = this.sampleValues, a = this.valueSize, o = 2 * a, l = 3 * a, h = n - e, c = (i - e) / h, d = c * c, u = d * c, p = t * l, m = p - l, f = -2 * u + 3 * d, g = u - d, v = 1 - f, _ = g - d + c; for (let t = 0; t !== a; t++) { const e = r[m + t + a], i = r[m + t + o] * h, n = r[p + t + a], l = r[p + t] * h; s[t] = v * e + _ * i + f * n + g * l } return s } } const jl = new ve; class Wl extends Hl { interpolate_(t, e, i, n) { const s = super.interpolate_(t, e, i, n); return jl.fromArray(s).normalize().toArray(s), s } } const Xl = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }, Yl = { 9728: et, 9729: st, 9984: it, 9985: 1007, 9986: nt, 9987: at }, ql = { 33071: Q, 33648: tt, 10497: J }, Zl = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }, $l = { POSITION: "position", NORMAL: "normal", TANGENT: "tangent", TEXCOORD_0: "uv", TEXCOORD_1: "uv2", COLOR_0: "color", WEIGHTS_0: "skinWeight", JOINTS_0: "skinIndex" }, Kl = { scale: "scale", translation: "position", rotation: "quaternion", weights: "morphTargetInfluences" }, Jl = { CUBICSPLINE: void 0, LINEAR: yt, STEP: xt }; function Ql(t, e, i) { for (const n in i.extensions) void 0 === t[n] && (e.userData.gltfExtensions = e.userData.gltfExtensions || {}, e.userData.gltfExtensions[n] = i.extensions[n]) } function th(t, e) { void 0 !== e.extras && "object" == typeof e.extras && Object.assign(t.userData, e.extras) } function eh(t, e) { if (t.updateMorphTargets(), void 0 !== e.weights) for (let i = 0, n = e.weights.length; i -1, s = n ? navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1] : -1; "undefined" == typeof createImageBitmap || i || n && s { const i = this.associations.get(t); null != i && this.associations.set(e, i); for (const [i, n] of t.children.entries()) s(n, e.children[i]) }; return s(i, n), n.name += "_instance_" + t.uses[e]++, n } _invokeOne(t) { const e = Object.values(this.plugins); e.push(this); for (let i = 0; i = 2 && p.setY(e, c[t * r + 1]), r >= 3 && p.setZ(e, c[t * r + 2]), r >= 4 && p.setW(e, c[t * r + 3]), r >= 5) throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.") } } return p })) } loadTexture(t) { const e = this.json, i = this.options, n = e.textures[t].source, s = e.images[n]; let r = this.textureLoader; if (s.uri) { const t = i.manager.getHandler(s.uri); null !== t && (r = t) } return this.loadTextureImage(t, n, r) } loadTextureImage(t, e, i) { const n = this, s = this.json, r = s.textures[t], a = s.images[e], o = (a.uri || a.bufferView) + ":" + r.sampler; if (this.textureCache[o]) return this.textureCache[o]; const l = this.loadImageSource(e, i).then((function (e) { e.flipY = !1, r.name && (e.name = r.name); const i = (s.samplers || {})[r.sampler] || {}; return e.magFilter = Yl[i.magFilter] || st, e.minFilter = Yl[i.minFilter] || at, e.wrapS = ql[i.wrapS] || J, e.wrapT = ql[i.wrapT] || J, n.associations.set(e, { textures: t }), e })).catch((function () { return null })); return this.textureCache[o] = l, l } loadImageSource(t, e) { const i = this.json, n = this.options; if (void 0 !== this.sourceCache[t]) return this.sourceCache[t].then((t => t.clone())); const s = i.images[t], r = self.URL || self.webkitURL; let a = s.uri || "", o = !1; if (void 0 !== s.bufferView) a = this.getDependency("bufferView", s.bufferView).then((function (t) { o = !0; const e = new Blob([t], { type: s.mimeType }); return a = r.createObjectURL(e), a })); else if (void 0 === s.uri) throw new Error("THREE.GLTFLoader: Image " + t + " is missing URI and bufferView"); const l = Promise.resolve(a).then((function (t) { return new Promise((function (i, s) { let r = i; !0 === e.isImageBitmapLoader && (r = function (t) { const e = new ue(t); e.needsUpdate = !0, i(e) }), e.load(Do.resolveURL(t, n.path), r, void 0, s) })) })).then((function (t) { var e; return !0 === o && r.revokeObjectURL(a), t.userData.mimeType = s.mimeType || ((e = s.uri).search(/\.jpe?g($|\?)/i) > 0 || 0 === e.search(/^data\:image\/jpeg/) ? "image/jpeg" : e.search(/\.webp($|\?)/i) > 0 || 0 === e.search(/^data\:image\/webp/) ? "image/webp" : "image/png"), t })).catch((function (t) { throw t })); return this.sourceCache[t] = l, l } assignTexture(t, e, i, n) { const s = this; return this.getDependency("texture", i.index).then((function (r) { if (void 0 !== i.texCoord && 0 != i.texCoord && ("aoMap" !== e || i.texCoord), s.extensions[_l]) { const t = void 0 !== i.extensions ? i.extensions[_l] : void 0; if (t) { const e = s.associations.get(r); r = s.extensions[_l].extendTexture(r, t), s.associations.set(r, e) } } return void 0 !== n && (r.encoding = n), t[e] = r, r })) } assignFinalMaterial(t) { const e = t.geometry; let i = t.material; const n = void 0 === e.attributes.tangent, s = void 0 !== e.attributes.color, r = void 0 === e.attributes.normal; if (t.isPoints) { const t = "PointsMaterial:" + i.uuid; let e = this.cache.get(t); e || (e = new Fa, Ri.prototype.copy.call(e, i), e.color.copy(i.color), e.map = i.map, e.sizeAttenuation = !1, this.cache.add(t, e)), i = e } else if (t.isLine) { const t = "LineBasicMaterial:" + i.uuid; let e = this.cache.get(t); e || (e = new Aa, Ri.prototype.copy.call(e, i), e.color.copy(i.color), this.cache.add(t, e)), i = e } if (n || s || r) { let t = "ClonedMaterial:" + i.uuid + ":"; i.isGLTFSpecularGlossinessMaterial && (t += "specular-glossiness:"), n && (t += "derivative-tangents:"), s && (t += "vertex-colors:"), r && (t += "flat-shading:"); let e = this.cache.get(t); e || (e = i.clone(), s && (e.vertexColors = !0), r && (e.flatShading = !0), n && (e.normalScale && (e.normalScale.y *= -1), e.clearcoatNormalScale && (e.clearcoatNormalScale.y *= -1)), this.cache.add(t, e), this.associations.set(e, this.associations.get(i))), i = e } i.aoMap && void 0 === e.attributes.uv2 && void 0 !== e.attributes.uv && e.setAttribute("uv2", e.attributes.uv), t.material = i } getMaterialType() { return ja } loadMaterial(t) { const e = this, i = this.json, n = this.extensions, s = i.materials[t]; let r; const a = {}, o = s.extensions || {}, l = []; if (o[cl]) { const t = n[cl]; r = t.getMaterialType(), l.push(t.extendParams(a, s, e)) } else if (o[fl]) { const t = n[fl]; r = t.getMaterialType(), l.push(t.extendParams(a, s, e)) } else { const i = s.pbrMetallicRoughness || {}; if (a.color = new ae(1, 1, 1), a.opacity = 1, Array.isArray(i.baseColorFactor)) { const t = i.baseColorFactor; a.color.fromArray(t), a.opacity = t[3] } void 0 !== i.baseColorTexture && l.push(e.assignTexture(a, "map", i.baseColorTexture, At)), a.metalness = void 0 !== i.metallicFactor ? i.metallicFactor : 1, a.roughness = void 0 !== i.roughnessFactor ? i.roughnessFactor : 1, void 0 !== i.metallicRoughnessTexture && (l.push(e.assignTexture(a, "metalnessMap", i.metallicRoughnessTexture)), l.push(e.assignTexture(a, "roughnessMap", i.metallicRoughnessTexture))), r = this._invokeOne((function (e) { return e.getMaterialType && e.getMaterialType(t) })), l.push(Promise.all(this._invokeAll((function (e) { return e.extendMaterialParams && e.extendMaterialParams(t, a) })))) } !0 === s.doubleSided && (a.side = 2); const h = s.alphaMode || "OPAQUE"; if ("BLEND" === h ? (a.transparent = !0, a.depthWrite = !1) : (a.transparent = !1, "MASK" === h && (a.alphaTest = void 0 !== s.alphaCutoff ? s.alphaCutoff : .5)), void 0 !== s.normalTexture && r !== Oi && (l.push(e.assignTexture(a, "normalMap", s.normalTexture)), a.normalScale = new Xt(1, 1), void 0 !== s.normalTexture.scale)) { const t = s.normalTexture.scale; a.normalScale.set(t, t) } return void 0 !== s.occlusionTexture && r !== Oi && (l.push(e.assignTexture(a, "aoMap", s.occlusionTexture)), void 0 !== s.occlusionTexture.strength && (a.aoMapIntensity = s.occlusionTexture.strength)), void 0 !== s.emissiveFactor && r !== Oi && (a.emissive = (new ae).fromArray(s.emissiveFactor)), void 0 !== s.emissiveTexture && r !== Oi && l.push(e.assignTexture(a, "emissiveMap", s.emissiveTexture, At)), Promise.all(l).then((function () { let i; return i = r === Bl ? n[cl].createMaterial(a) : new r(a), s.name && (i.name = s.name), th(i, s), e.associations.set(i, { materials: t }), s.extensions && Ql(n, i, s), i })) } createUniqueName(t) { const e = Bo.sanitizeNodeName(t || ""); let i = e; for (let t = 1; this.nodeNamesUsed[i]; ++t)i = e + "_" + t; return this.nodeNamesUsed[i] = !0, i } loadGeometries(t) { const e = this, i = this.extensions, n = this.primitiveCache; function s(t) { return i[al].decodePrimitive(t, e).then((function (i) { return oh(i, t, e) })) } const r = []; for (let i = 0, a = t.length; i 0 && eh(d, s), d.name = e.createUniqueName(s.name || "mesh_" + t), th(d, s), c.extensions && Ql(n, d, c), e.assignFinalMaterial(d), l.push(d) } for (let i = 0, n = l.length; i 1 ? new sa : 1 === e.length ? e[0] : new yi, a !== e[0]) for (let t = 0, i = e.length; t { const e = new Map; for (const [t, i] of s.associations) (t instanceof Ri || t instanceof ue) && e.set(t, i); return t.traverse((t => { const i = s.associations.get(t); null != i && e.set(t, i) })), e })(r), r })) } } function ah(t, e, i, n) { const s = i.nodes[t]; return n.getDependency("node", t).then((function (t) { if (void 0 === s.skin) return t; let e; return n.getDependency("skin", s.skin).then((function (t) { e = t; const i = []; for (let t = 0, s = e.joints.length; t { const e = t.draco, a = new e.Decoder, o = new e.DecoderBuffer; o.Init(new Int8Array(n), n.byteLength); try { const t = function (t, e, n, s) { const r = s.attributeIDs, a = s.attributeTypes; let o, l; const h = e.GetEncodedGeometryType(n); if (h === t.TRIANGULAR_MESH) o = new t.Mesh, l = e.DecodeBufferToMesh(n, o); else { if (h !== t.POINT_CLOUD) throw new Error("THREE.DRACOLoader: Unexpected geometry type."); o = new t.PointCloud, l = e.DecodeBufferToPointCloud(n, o) } if (!l.ok() || 0 === o.ptr) throw new Error("THREE.DRACOLoader: Decoding failed: " + l.error_msg()); const c = { index: null, attributes: [] }; for (const n in r) { const l = self[a[n]]; let h, d; if (s.useUniqueIDs) d = r[n], h = e.GetAttributeByUniqueId(o, d); else { if (d = e.GetAttributeId(o, t[r[n]]), -1 === d) continue; h = e.GetAttribute(o, d) } c.attributes.push(i(t, e, o, n, l, h)) } return h === t.TRIANGULAR_MESH && (c.index = function (t, e, i) { const n = 3 * i.num_faces(), s = 4 * n, r = t._malloc(s); e.GetTrianglesUInt32Array(i, s, r); const a = new Uint32Array(t.HEAPF32.buffer, r, n).slice(); return t._free(r), { array: a, itemSize: 1 } }(t, e, o)), t.destroy(o), c }(e, a, o, r), n = t.attributes.map((t => t.array.buffer)); t.index && n.push(t.index.array.buffer), self.postMessage({ type: "decode", id: s.id, geometry: t }, n) } catch (t) { self.postMessage({ type: "error", id: s.id, error: t.message }) } finally { e.destroy(o), e.destroy(a) } })) } } } const dh = new lo, uh = new class extends co { constructor(t) { super(t), this.decoderPath = "", this.decoderConfig = {}, this.decoderBinary = null, this.decoderPending = null, this.workerLimit = 4, this.workerPool = [], this.workerNextTaskID = 1, this.workerSourceURL = "", this.defaultAttributeIDs = { position: "POSITION", normal: "NORMAL", color: "COLOR", uv: "TEX_COORD" }, this.defaultAttributeTypes = { position: "Float32Array", normal: "Float32Array", color: "Float32Array", uv: "Float32Array" } } setDecoderPath(t) { return this.decoderPath = t, this } setDecoderConfig(t) { return this.decoderConfig = t, this } setWorkerLimit(t) { return this.workerLimit = t, this } load(t, e, i, n) { const s = new po(this.manager); s.setPath(this.path), s.setResponseType("arraybuffer"), s.setRequestHeader(this.requestHeader), s.setWithCredentials(this.withCredentials), s.load(t, (t => { const i = { attributeIDs: this.defaultAttributeIDs, attributeTypes: this.defaultAttributeTypes, useUniqueIDs: !1 }; this.decodeGeometry(t, i).then(e).catch(n) }), i, n) } decodeDracoFile(t, e, i, n) { const s = { attributeIDs: i || this.defaultAttributeIDs, attributeTypes: n || this.defaultAttributeTypes, useUniqueIDs: !!i }; this.decodeGeometry(t, s).then(e) } decodeGeometry(t, e) { for (const t in e.attributeTypes) { const i = e.attributeTypes[t]; void 0 !== i.BYTES_PER_ELEMENT && (e.attributeTypes[t] = i.name) } const i = JSON.stringify(e); if (hh.has(t)) { const e = hh.get(t); if (e.key === i) return e.promise; if (0 === t.byteLength) throw new Error("THREE.DRACOLoader: Unable to re-decode a buffer with different settings. Buffer has already been transferred.") } let n; const s = this.workerNextTaskID++, r = t.byteLength, a = this._getWorker(s, r).then((i => (n = i, new Promise(((i, r) => { n._callbacks[s] = { resolve: i, reject: r }, n.postMessage({ type: "decode", id: s, taskConfig: e, buffer: t }, [t]) }))))).then((t => this._createGeometry(t.geometry))); return a.catch((() => !0)).then((() => { n && s && this._releaseTask(n, s) })), hh.set(t, { key: i, promise: a }), a } _createGeometry(t) { const e = new qi; t.index && e.setIndex(new Fi(t.index.array, 1)); for (let i = 0; i { i.load(t, e, void 0, n) })) } preload() { return this._initDecoder(), this } _initDecoder() { if (this.decoderPending) return this.decoderPending; const t = "object" != typeof WebAssembly || "js" === this.decoderConfig.type, e = []; return t ? e.push(this._loadLibrary("draco_decoder.js", "text")) : (e.push(this._loadLibrary("draco_wasm_wrapper.js", "text")), e.push(this._loadLibrary("draco_decoder.wasm", "arraybuffer"))), this.decoderPending = Promise.all(e).then((e => { const i = e[0]; t || (this.decoderConfig.wasmBinary = e[1]); const n = ch.toString(), s = ["/* draco decoder */", i, "", "/* worker */", n.substring(n.indexOf("{") + 1, n.lastIndexOf("}"))].join("\n"); this.workerSourceURL = URL.createObjectURL(new Blob([s])) })), this.decoderPending } _getWorker(t, e) { return this._initDecoder().then((() => { if (this.workerPool.length e._taskLoad ? -1 : 1 })); const i = this.workerPool[this.workerPool.length - 1]; return i._taskCosts[t] = e, i._taskLoad += e, i })) } _releaseTask(t, e) { t._taskLoad -= t._taskCosts[e], delete t._callbacks[e], delete t._taskCosts[e] } debug() { } dispose() { for (let t = 0; t =2.0 are supported."))); const l = new rh(o, { path: e || this.resourcePath || "", crossOrigin: this.crossOrigin, requestHeader: this.requestHeader, manager: this.manager, ktx2Loader: this.ktx2Loader, meshoptDecoder: this.meshoptDecoder }); l.fileLoader.setRequestHeader(this.requestHeader); for (let t = 0; t = 0 && a[e] } } l.setExtensions(r), l.setPlugins(a), l.parse(i, n) } parseAsync(t, e) { const i = this; return new Promise((function (n, s) { i.parse(t, e, n, s) })) } }(dh), mh = new class extends fo { constructor(t) { super(t), this.type = ct } parse(t) { const e = function (t, e, i) { e = e || 1024; let n = t.pos, s = -1, r = 0, a = "", o = String.fromCharCode.apply(null, new Uint16Array(t.subarray(n, n + 128))); for (; 0 > (s = o.indexOf("\n")) && r = t.byteLength || !(o = e(t))) return -1; if (!(l = o.match(/^#\?(\S+)/))) return -1; for (a.valid |= 1, a.programtype = l[1], a.string += o + "\n"; o = e(t), !1 !== o;)if (a.string += o + "\n", "#" !== o.charAt(0)) { if ((l = o.match(i)) && (a.gamma = parseFloat(l[1])), (l = o.match(n)) && (a.exposure = parseFloat(l[1])), (l = o.match(s)) && (a.valid |= 2, a.format = l[1]), (l = o.match(r)) && (a.valid |= 4, a.height = parseInt(l[1], 10), a.width = parseInt(l[2], 10)), 2 & a.valid && 4 & a.valid) break } else a.comments += o + "\n"; return 2 & a.valid && 4 & a.valid ? a : -1 }(s); if (-1 !== r) { const t = r.width, e = r.height, a = function (t, e, i) { const n = e; if (n 32767 || 2 !== t[0] || 2 !== t[1] || 128 & t[2]) return new Uint8Array(t); if (n !== (t[2] 0 && a t.byteLength) return -1; if (l[0] = t[a++], l[1] = t[a++], l[2] = t[a++], l[3] = t[a++], 2 != l[0] || 2 != l[1] || (l[2] 128; if (n && (e -= 128), 0 === e || i + e > o) return -1; if (n) { const n = t[a++]; for (let t = 0; t { t.frustumCulled = !1, t.isMesh && (t.castShadow = !0, t.receiceShadow = !1, t.material.map && (t.material.map.colorSpace = Et, t.material.map.format = ut, t.material.map.type = ot, t.material.needsUpdate = !0)), "Display_ActiveArea" == t.name && (this.screen = t, this.screen.type = "default", this.screen.material.color0 = this.screen.material.color.clone(), this.screen.material.envMapIntensity0 = this.screen.material.envMapIntensity, this.screen.material.emissive0 = this.screen.material.emissive, this.screen.material.emissiveIntensity0 = this.screen.material.emissiveIntensity), "Display_ActiveArea_Front" == t.name && (this.screenFront = t, this.screenFront.type = "front", this.screenFront.material.color0 = this.screenFront.material.color.clone(), this.screenFront.material.emissive0 = this.screenFront.material.emissive, this.screenFront.material.envMapIntensity0 = this.screenFront.material.envMapIntensity, this.screenFront.material.emissiveIntensity0 = this.screenFront.material.emissiveIntensity), "Display_ActiveArea_cam" == t.name && t.material.userData.screenToggleStatus && (this.screenCam = t, this.screenCam.type = "cam", this.screenCam.material.color0 = this.screenCam.material.color.clone(), this.screenCam.material.emissive0 = this.screenCam.material.emissive, this.screenCam.material.envMapIntensity0 = this.screenCam.material.envMapIntensity, this.screenCam.material.emissiveIntensity0 = this.screenCam.material.emissiveIntensity) })), this.handleScreen = function (t, e, i = !1) { if (null != t) switch (e) { case 1: t.material.color = t.material.color0.clone(), t.material.emissiveIntensity = t.material.emissiveIntensity0, t.material.envMapIntensity = t.material.envMapIntensity0; break; case 0: t.material.emissiveIntensity = 0, t.material.envMapIntensity = i ? 0 : t.material.envMapIntensity0, (this.modelData.screenOffColor || vh.indexOf(this.modelName) > -1) && t.material.color.set(this.modelData.screenOffColor) } }, this.screenDefaultOn = function (t = !1) { this.modelOption.screen && (this.handleScreen(this.screen, 1), this.screenCam && this.handleScreen(this.screenCam, 1)) }, this.screenDefaultOff = function (t = !1) { this.handleScreen(this.screen, 0, t), this.screenCam && this.handleScreen(this.screenCam, 0) }, this.screenFrontOn = function (t = !1) { this.modelOption.screen && this.handleScreen(this.screenFront, 1) }, this.screenFrontOff = function (t = !1) { this.handleScreen(this.screenFront, 0) }, this.screenOn = function (t = !1) { this.modelOption.screen && (this.screenDefaultOn(), this.screenFrontOn()) }, this.screenOff = function (t = !1) { this.screenDefaultOff(), this.screenFrontOff() }, this.screenUpdate = function () { if ("on" === this.modelOption.screenMode) return this.screenDefaultOn(), void this.screenFrontOn(); if ("off" === this.modelOption.screenMode) return this.screenDefaultOff(), void this.screenFrontOff(); if (!this.modelData.isSample) if (this.mixer) { const t = this.mixer.getTrack(); switch (this.toggleScreenDirection) { case 1: t > .1 ? this.modelOption.screen ? this.screenDefaultOn() : this.screenDefaultOff() : this.screenDefaultOff(!0), t .1 && this.modelOption.screen ? this.screenFrontOn() : this.screenFrontOff(), t 0 ? 1 : -1, h = this; let c; this.isAnimation = !0, this.frame = requestAnimationFrame((function t(n) { null == c && (c = n); const s = a + (n - c) * (o - a) / r; if (-1 == l && s = o || s >= h.duration || s i.toggleActionSetTime(.14, 400, !0)), 350) }, 1700: function () { i.statusToggleInactive(!0), setTimeout((() => i.setPosition({ angleX: 0, angleY: u(-100), zoom: 30 }, 600, void 0, void 0, void 0, !0)), 30) }, 3400: function () { i.setPosition({ angleY: u(-360) }, 1400, void 0, void 0, void 0, !0) }, 5100: function () { } } }, 2: { actions: { 0: function () { i.setPosition({ angleX: u(-40), angleY: u(30), panY: -2 }, 560, void 0, void 0, void 0, !0), setTimeout((() => i.toggleActionSetTime(.14, 400, !0)), 70) }, 1600: function () { i.toggleActionSetTime(0, 300, !0), i.setPosition({ angleX: 0, angleY: u(-132), panY: 0 }, 600, void 0, void 0, void 0, !0) }, 3200: function () { i.setPosition({ angleY: u(-360) }, 650, void 0, void 0, void 0, !0) }, 5e3: function () { } } }, 3: { actions: { 0: function () { i.setPosition({ angleX: u(-40), angleY: u(30), panY: -2 }, 560, void 0, void 0, void 0, !0), setTimeout((() => i.toggleActionSetTime(.15, 0, !0)), 50), setTimeout((() => i.toggleActionSetTime(.21, 130, !0)), 50), setTimeout((() => i.toggleActionSetTime(.38, 320, !0)), 150) }, 1600: function () { i.toggleActionSetTime(0, 300, !0), i.setPosition({ angleX: 0, angleY: u(-132), panY: 0 }, 600, void 0, void 0, void 0, !0) }, 3200: function () { i.setPosition({ angleY: u(-360) }, 650, void 0, void 0, void 0, !0) }, 5e3: function () { } } }, "20251h": { startPose: function () { }, actions: { 0: function () { i.setPosition({ angleY: u(-135) }, 560, void 0, void 0, void 0, !0) }, 600: function () { } } } }, fold: { default: { actions: { 0: function () { i.statusToggleActive(!0) }, 1700: function () { i.setPosition({ angleY: u(138) }, 500, void 0, void 0, void 0, !0) }, 3400: function () { i.statusToggleInactive(!0), i.setPosition({ angleX: 0, angleY: 0, angleZ: 0 }, 500, void 0, void 0, void 0, !0) }, 5100: function () { } } }, 2: { actions: { 0: function () { i.setPosition({ angleX: 0, angleY: u(-245), angleZ: 0, angleLimit: !1 }, 800, "easeInOutSine", void 0, void 0, !0) }, 800: function () { i.setPosition({ angleX: 0, angleY: u(-360), angleZ: 0, angleLimit: !1 }, 568, "easeNone", void 0, void 0, !0), i.toggleActionSetTime(1, 560, !0) }, 1360: function () { i.setPosition({ angleX: 0, angleY: u(-390), angleZ: 0, angleLimit: !1 }, 1120, "easeInSine", void 0, void 0, !0) }, 2480: function () { i.setPosition({ angleX: 0, angleY: u(-720), angleZ: 0, angleLimit: !1 }, 880, "easeOutQuad", void 0, void 0, !0), i.toggleActionSetTime(.65, 240, !0) }, 2720: function () { i.toggleActionSetTime(0, 680, !0) }, 4e3: function () { } } }, 3: { startPose: function () { i.toggleActionSetTime(0, 0, !0), i.screenUpdate() }, actions: { 0: function () { i.setPosition({ angleX: 0, angleY: u(0), angleZ: 0, angleLimit: !1 }, 600, "easeInOutSine", void 0, void 0, !0) }, 700: function () { i.toggleActionSetTime(1, 600, !0) }, 1400: function () { i.setPosition({ angleX: 0, angleY: u(-180), angleZ: 0, angleLimit: !1 }, 800, "easeOut", void 0, void 0, !0) }, 2e3: function () { i.toggleActionSetTime(.7, 400, !0), i.setPosition({ angleX: 0, angleY: u(-200), angleZ: 0, angleLimit: !1 }, 400, "easeInOut", void 0, void 0, !0) }, 2700: function () { } } } }, flip: { default: { actions: { 0: function () { i.setPosition({ angleX: u(-67), angleY: u(4), angleZ: u(54) }, 500, void 0, void 0, void 0, !0), i.toggleActionSetTime(.58, 350, !0) }, 1700: function () { i.setPosition({ angleX: 0, angleY: u(0), angleZ: u(0) }, 500, void 0, void 0, void 0, !0), i.statusToggleActive(!0) }, 3400: function () { i.reset(), i.statusToggleInactive(!0) }, 5100: function () { } } }, 2: { startPose: function () { i.toggleActionSetTime(1, 0, !0), i.screenUpdate() }, actions: { 0: function () { i.cameraControls.rotateLeft(u(-360), 1920, "easeInSine") }, 960: function () { i.setPosition({ angleX: u(-90), poseY: -1.5 }, 960, "easeOutQuint", void 0, void 0, !0), i.toggleActionSetTime(.457, 320, !0) }, 1840: function () { i.cameraControls.rotateLeft(u(-70), 1120, "easeNone") }, 2960: function () { i.cameraControls.rotateLeft(u(-360), 1040, "easeOutQuart") }, 3040: function () { i.setPosition({ angleX: 0, poseY: 0 }, 720, "easeInOutQuad", void 0, void 0, !0), i.toggleActionSetTime(0, 640, !0) }, 4e3: function () { } } }, 3: { startPose: function () { i.toggleActionSetTime(0, 0, !0), i.screenUpdate() }, actions: { 0: function () { i.toggleActionSetTime(1, 800, !0), i.setPosition({ angleX: 0, angleY: u(0), angleZ: 0, angleLimit: !1 }, 800, "easeInOutSine", void 0, void 0, !0) }, 900: function () { i.toggleActionSetTime(0, 800, !0) }, 1800: function () { i.setPosition({ angleX: 0, angleY: u(-180), angleZ: 0, angleLimit: !1 }, 800, "easeInOutSine", void 0, void 0, !0) }, 2700: function () { } } } } }; return n[t] ? n[t][e] ? n[t][e] : n[t].default : void 0 } new yh({ angleX: 0, angleY: 0, angleZ: 0, zoom: E, panX: 0, panY: 0, angleLimit: !1 }); const Mh = "easeOutCubic", wh = !0; let Sh; class Th extends Rt { constructor(t) { super(), this.isRun = !1, this.controls = t, this.controls.cameraControls = this, this.camera = this.controls.object, this.productObject = this.controls.productObject, this.target = new _e(this.controls.productObject.x, 0, this.controls.productObject.z), this.callback = null, this.duration = 700, this.startTime = Date.now(), this.easing = Mh, this.angleLimit = wh, this.startAngle, this.endAngle, this.startSpherical = new jo, this.prevSpherical = new jo, this.endSpherical = new jo, this.endPosition = new _e, this.prevPosition = new _e, this.spherical = new jo, this.sphericalDelta = new jo, this.angle = null, Sh = (new ve).setFromUnitVectors(this.camera.up, new _e(0, 1, 0)) } rotateLeft(t, e, i, n, s, r = !1) { if (null == t) return; s = s || {}; const a = new _e; if (a.copy(this.camera.position).sub(this.target), a.applyQuaternion(Sh), this.startTime = Date.now(), this.angle = -1 * t, this.startSpherical = (new jo).setFromVector3(a), this.endSpherical = (new jo).copy(this.startSpherical), this.endSpherical.theta = this.angle, this.duration = null == e ? 700 : e, this.easing = null == i ? Mh : i, this.angleLimit = null == s.angleLimit ? wh : s.angleLimit, this.spherical.setFromVector3(a), 0 == this.duration) return this.spherical.theta += this.angle, void this.camera.position.setFromSpherical(this.spherical); this.rotateStart() } rotateStart() { this.isRun = !0 } rotateEnd() { this.isRun = !1 } update() { if (!this.isRun) return; let t = (Date.now() - this.startTime) / this.duration; t > 1 && (t = 1); let e = (this.endSpherical.theta - this.startSpherical.theta) * g(this.easing, t), i = this.startSpherical.clone(); i.theta = this.startSpherical.theta + e, this.camera.position.setFromSpherical(i), (i.thera == this.endSpherical.theta || t >= 1) && this.rotateEnd() } reset() { this.rotateLeft(0, 500) } clear() { } } const Ah = "easeOutCubic", Eh = 700, Ph = !0, Ch = !1, Lh = !0; class Dh { constructor(t, e) { this.enabled = !0, this.isZoom = !1, this.izRotation = !1, this.isPan = !1, this.isRun = !1, this.controls = t, this.controls.setPositionControls = this, this.productObject = e || this.controls.productObject, this.camera = this.controls.object, this.target = this.controls.target, this.allowCanceled = !0, this.callback = null, this.duration = Eh, this.startTime = Date.now(), this.easing = Ah, this.dampingFactor = .05, this.calcAngle = Ch, this.angleLimit = Lh, this.startPosition = new yh, this.endPosition = new yh, this.prevRotate = new _e, this.prevPosition = new _e, this.cameraLock = !!this.controls.cameraControls.isRun } setPosition(t, e, i, n, s, r = !1) { if (s = s || {}, this.isRun = !0, this.isZoom = void 0 !== t.zoom, this.callback = n, this.easing = null == i ? Ah : i, this.duration = null == e ? Eh : e, this.allowCanceled = void 0 !== s.allowCanceled ? s.allowCanceled : this.allowCanceled, this.cameraLock = !!this.controls.cameraControls.isRun, this.set(t), 0 == this.duration) return this.productObject.rotation.x = this.endPosition.angleX, this.productObject.rotation.y = this.endPosition.angleY, this.productObject.rotation.z = this.endPosition.angleZ, this.productObject.position.x = this.endPosition.poseX, this.productObject.position.y = this.endPosition.poseY, this.productObject.position.z = this.endPosition.poseZ, this.camera.position.x = this.endPosition.panX, this.camera.position.y = this.endPosition.panY, this.camera.position.z = this.endPosition.zoom, this.target.x = this.endPosition.panX, this.target.y = this.endPosition.panY, void this.positionEnd(); this.positionStart() } set(t) { this.angleLimit = void 0 !== t.angleLimit ? t.angleLimit : Lh, this.startPosition.angleX = this.angleLimit ? p(this.productObject.rotation.x) : this.productObject.rotation.x, this.startPosition.angleY = this.angleLimit ? p(this.productObject.rotation.y) : this.productObject.rotation.y, this.startPosition.angleZ = this.angleLimit ? p(this.productObject.rotation.z) : this.productObject.rotation.z, this.startPosition.poseX = this.productObject.position.x, this.startPosition.poseY = this.productObject.position.y, this.startPosition.poseZ = this.productObject.position.z, this.startPosition.panX = this.camera.position.x || 0, this.startPosition.panY = this.camera.position.y || 0, this.startPosition.zoom = this.camera.position.z || E, this.endPosition.angleX = void 0 !== t.angleX ? t.angleX : this.startPosition.angleX, this.endPosition.angleY = void 0 !== t.angleY ? t.angleY : this.startPosition.angleY, this.endPosition.angleZ = void 0 !== t.angleZ ? t.angleZ : this.startPosition.angleZ, this.endPosition.poseX = void 0 !== t.poseX ? t.poseX : this.startPosition.poseX, this.endPosition.poseY = void 0 !== t.poseY ? t.poseY : this.startPosition.poseY, this.endPosition.poseZ = void 0 !== t.poseZ ? t.poseZ : this.startPosition.poseZ, this.endPosition.panX = void 0 !== t.panX ? t.panX : this.startPosition.panX, this.endPosition.panY = void 0 !== t.panY ? t.panY : this.startPosition.panY, this.endPosition.zoom = void 0 !== t.zoom ? t.zoom : this.startPosition.zoom, this.calcAngle = void 0 !== t.calcAngle ? t.calcAngle : Ch } positionStart() { this.startTime = Date.now(), this.controls.setPositionStart() } positionEnd() { this.isRun = !1, this.callback && this.callback(), this.startPosition = this.endPosition.clone(), this.allowCanceled = Ph, this.calcAngle = Ch, this.angleLimit = Lh, this.callback = null } stop() { this.positionEnd() } update() { if (!this.enabled) return; if (!this.isRun) return; const t = (Date.now() - this.startTime) / this.duration; if (!0 !== this.cameraLock && this.camera.position.z !== this.endPosition.zoom && this.isZoom) { const e = this.startPosition.zoom; let i = this.endPosition.zoom - e, n = i * g(this.easing, t); n = Math.abs(n) > Math.abs(i) || t >= 1 ? i : n, this.camera.position.z = e + n } if (this.productObject.rotation.x !== this.endPosition.angleX || this.productObject.rotation.y !== this.endPosition.angleY || this.productObject.rotation.z !== this.endPosition.angleZ) { let e = this.endPosition.angleX - this.startPosition.angleX, i = this.endPosition.angleY - this.startPosition.angleY, n = this.endPosition.angleZ - this.startPosition.angleZ, s = e * g(this.easing, t), r = i * g(this.easing, t), a = n * g(this.easing, t); s = Math.abs(s) > Math.abs(e) || t >= 1 ? e : s, r = Math.abs(r) > Math.abs(i) || t >= 1 ? i : r, a = Math.abs(a) > Math.abs(n) || t >= 1 ? n : a, this.prevRotate.x = this.startPosition.angleX + s, this.prevRotate.y = this.startPosition.angleY + r, this.prevRotate.z = this.startPosition.angleZ + a, this.angleLimit && (this.prevRotate.x = p(this.prevRotate.x), this.prevRotate.y = p(this.prevRotate.y), this.prevRotate.z = p(this.prevRotate.z)), this.productObject.rotation.x = this.prevRotate.x, this.productObject.rotation.z = this.prevRotate.z, this.productObject.rotation.y = this.calcAngle ? m(this.prevRotate, this.productObject.position.x, this.camera.position.z) : this.prevRotate.y } if ((this.camera.position.x !== this.endPosition.panX || this.camera.position.y !== this.endPosition.panY) && !0 !== this.cameraLock) { let e = this.endPosition.panX - this.startPosition.panX, i = this.endPosition.panY - this.startPosition.panY, n = e * g(this.easing, t), s = i * g(this.easing, t); n = Math.abs(n) > Math.abs(e) || t >= 1 ? e : n, s = Math.abs(s) > Math.abs(i) || t >= 1 ? i : s, this.target.x = this.startPosition.panX + n, this.target.y = this.startPosition.panY + s, this.camera.position.x = this.startPosition.panX + n, this.camera.position.y = this.startPosition.panY + s } if (this.productObject.position.x !== this.endPosition.poseX || this.productObject.position.y !== this.endPosition.poseY || this.productObject.position.z !== this.endPosition.poseZ) { let e = this.endPosition.poseX - this.startPosition.poseX, i = this.endPosition.poseY - this.startPosition.poseY, n = this.endPosition.poseZ - this.startPosition.poseZ, s = e * g(this.easing, t), r = i * g(this.easing, t), a = n * g(this.easing, t); s = Math.abs(s) > Math.abs(e) || t >= 1 ? e : s, r = Math.abs(r) > Math.abs(i) || t >= 1 ? i : r, a = Math.abs(a) > Math.abs(n) || t >= 1 ? n : a, this.prevPosition.x = this.startPosition.poseX + s, this.prevPosition.y = this.startPosition.poseY + r, this.prevPosition.z = this.startPosition.poseZ + a, this.productObject.position.x = this.prevPosition.x, this.productObject.position.y = this.prevPosition.y, this.productObject.position.z = this.prevPosition.z } (this.camera.position.z == this.endPosition.zoom && !0 !== this.cameraLock && this.productObject.rotation.x == this.endPosition.angleX && this.prevRotate.y == this.endPosition.angleY && this.productObject.rotation.z == this.endPosition.angleZ && this.camera.position.x == this.endPosition.panX && this.camera.position.y == this.endPosition.panY && !0 !== this.cameraLock || t > 1) && (this.isRun = !1, this.positionEnd()) } rotateLeft(t) { } rotateRight(t) { } } class Ih { constructor(t, e) { this.enabled = !0, this.isZoom = !1, this.izRotation = !1, this.isPan = !1, this.isRun = !1, this.controls = t, this.controls.setPositionController.list.push(this), this.gltfObject = e, this.camera = this.controls.object, this.target = this.controls.target, this.allowCanceled = !0, this.callback = null, this.duration = Eh, this.startTime = Date.now(), this.easing = Ah, this.dampingFactor = .05, this.calcAngle = Ch, this.angleLimit = Lh, this.startPosition = new yh, this.endPosition = new yh, this.prevRotate = new _e, this.prevPosition = new _e } setPosition(t, e, i, n, s, r = !1) { if (s = s || {}, this.isRun = !0, this.isZoom = void 0 !== t.zoom, this.callback = n, this.easing = null == i ? Ah : i, this.duration = null == e ? Eh : e, this.allowCanceled = void 0 !== s.allowCanceled ? s.allowCanceled : this.allowCanceled, this.set(t), 0 == this.duration) return this.gltfObject.rotation.x = this.endPosition.angleX, this.gltfObject.rotation.y = this.endPosition.angleY, this.gltfObject.rotation.z = this.endPosition.angleZ, this.gltfObject.position.x = this.endPosition.poseX, this.gltfObject.position.y = this.endPosition.poseY, this.gltfObject.position.z = this.endPosition.poseZ, void this.positionEnd(); this.positionStart() } set(t) { this.angleLimit = void 0 !== t.angleLimit ? t.angleLimit : Lh, this.startPosition.angleX = this.angleLimit ? p(this.gltfObject.rotation.x) : this.gltfObject.rotation.x, this.startPosition.angleY = this.angleLimit ? p(this.gltfObject.rotation.y) : this.gltfObject.rotation.y, this.startPosition.angleZ = this.angleLimit ? p(this.gltfObject.rotation.z) : this.gltfObject.rotation.z, this.startPosition.poseX = this.gltfObject.position.x, this.startPosition.poseY = this.gltfObject.position.y, this.startPosition.poseZ = this.gltfObject.position.z, this.endPosition.angleX = void 0 !== t.angleX ? t.angleX : this.startPosition.angleX, this.endPosition.angleY = void 0 !== t.angleY ? t.angleY : this.startPosition.angleY, this.endPosition.angleZ = void 0 !== t.angleZ ? t.angleZ : this.startPosition.angleZ, this.endPosition.poseX = void 0 !== t.poseX ? t.poseX : this.startPosition.poseX, this.endPosition.poseY = void 0 !== t.poseY ? t.poseY : this.startPosition.poseY, this.endPosition.poseZ = void 0 !== t.poseZ ? t.poseZ : this.startPosition.poseZ, this.calcAngle = void 0 !== t.calcAngle ? t.calcAngle : Ch } positionStart() { this.startTime = Date.now(), this.controls.setPositionStart() } positionEnd() { this.isRun = !1, this.callback && this.callback(), this.startPosition = this.endPosition.clone(), this.allowCanceled = Ph, this.calcAngle = Ch, this.angleLimit = Lh, this.callback = null } stop() { this.positionEnd() } update() { if (!this.enabled) return; if (!this.isRun) return; const t = (Date.now() - this.startTime) / this.duration; if (this.gltfObject.rotation.x !== this.endPosition.angleX || this.gltfObject.rotation.y !== this.endPosition.angleY || this.gltfObject.rotation.z !== this.endPosition.angleZ) { let e = this.endPosition.angleX - this.startPosition.angleX, i = this.endPosition.angleY - this.startPosition.angleY, n = this.endPosition.angleZ - this.startPosition.angleZ, s = e * g(this.easing, t), r = i * g(this.easing, t), a = n * g(this.easing, t); s = Math.abs(s) > Math.abs(e) || t >= 1 ? e : s, r = Math.abs(r) > Math.abs(i) || t >= 1 ? i : r, a = Math.abs(a) > Math.abs(n) || t >= 1 ? n : a, this.prevRotate.x = this.startPosition.angleX + s, this.prevRotate.y = this.startPosition.angleY + r, this.prevRotate.z = this.startPosition.angleZ + a, this.angleLimit && (this.prevRotate.x = p(this.prevRotate.x), this.prevRotate.y = p(this.prevRotate.y), this.prevRotate.z = p(this.prevRotate.z)), this.gltfObject.rotation.x = this.prevRotate.x, this.gltfObject.rotation.z = this.prevRotate.z, this.gltfObject.rotation.y = this.calcAngle ? m(this.prevRotate, this.gltfObject.position.x, this.camera.position.z) : this.prevRotate.y } if (this.gltfObject.position.x !== this.endPosition.poseX || this.gltfObject.position.y !== this.endPosition.poseY || this.gltfObject.position.z !== this.endPosition.poseZ) { let e = this.endPosition.poseX - this.startPosition.poseX, i = this.endPosition.poseY - this.startPosition.poseY, n = this.endPosition.poseZ - this.startPosition.poseZ, s = e * g(this.easing, t), r = i * g(this.easing, t), a = n * g(this.easing, t); s = Math.abs(s) > Math.abs(e) || t >= 1 ? e : s, r = Math.abs(r) > Math.abs(i) || t >= 1 ? i : r, a = Math.abs(a) > Math.abs(n) || t >= 1 ? n : a, this.prevPosition.x = this.startPosition.poseX + s, this.prevPosition.y = this.startPosition.poseY + r, this.prevPosition.z = this.startPosition.poseZ + a, this.gltfObject.position.x = this.prevPosition.x, this.gltfObject.position.y = this.prevPosition.y, this.gltfObject.position.z = this.prevPosition.z } (this.gltfObject.rotation.x == this.endPosition.angleX && this.prevRotate.y == this.endPosition.angleY && this.gltfObject.rotation.z == this.endPosition.angleZ || t > 1) && (this.isRun = !1, this.positionEnd()) } } class Rh extends sa { constructor(t, e, { container: i, scene: n, renderer: s, camera: r, viewer: a }) { super(), this.OPTIONS = t, this.productData = e, this.container = i, this.scene = n, this.renderer = s, this.camera = r, this.viewer = a, this.cameraControls = null, this.positionControls = null, this.isInit = !1, this.frustumCulled = !1 } init() { this.isInit || (this.cameraControls = new cameraControls(this.viewer.controls), this.positionControls = new positionControls(this.viewer.controls), this.isInit = !0) } setViewerEncoding() { "sRGB" == this.productData.getModelData(this.children[0].modelName)["output-rendering"] ? (this.renderer.toneMapping = ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1.2, this.renderer.textureEncoding = sRGBEncoding, this.renderer.outputEncoding = sRGBEncoding) : (this.renderer.toneMapping = NoToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.textureEncoding = LinearEncoding, this.renderer.outputEncoding = LinearEncoding) } getTargetObject(t) { return this.children.find((e => e.modelName === t)) } } const Oh = {}, Nh = {}; class zh { constructor(t, e, { container: i, scene: n, renderer: s, camera: r, viewer: a }) { const o = this; this.enabled = !1, this.userControl = !1, this.OPTIONS = t, this.productData = e, this.container = i, this.viewer = a, this.scene = n, this.renderer = s, this.camera = r, this.product = e.product, this.defaultModelName = e.getDefaultModelName(), this.defaultColorName = e.getDefaultColorName(this.defaultModelName), this.positionControls = null, this.cameraControls = null, this.modelData = null, this.colorName = null, this.modelScale = null, this.modelGroup = new Rh(this.OPTIONS, this.productData, { scene: this.scene, renderer: this.renderer, camera: this.camera, container: this.container, uiControls: this.uiControls, viewer: this }), this.modelGroup.rotation.set(this.OPTIONS.y, this.OPTIONS.x, 0), this.isInit = !1, this.isProductChange = !1, this.isMixerRun = !1, this.environmentHdrName = null, this.introPoseReady = !1, this.introPoseEnd = !1, this.modelPathBackup = this.OPTIONS.assetsPath + "models/", this.modelPathMath = { [this.modelPathBackup]: Object.values(A)[0] }, this.toggleScreenDirection = 0, this.initPosition = new yh({ angleX: this.OPTIONS.y || 0, angleY: this.OPTIONS.x || 0, angleZ: 0, zoom: f(this.OPTIONS.zoom) || E, panX: 0, panY: 0, angleLimit: !1 }), this.initPosition0 = this.initPosition.clone(), this.startPosition = this.initPosition.clone(), this.introPoseUsedData = JSON.parse(l(R)) || {}, this.autoRotation = function () { const t = 1700, e = !1; let i = {}; return { duration: t, allowCanceled: e, isRunning: function () { return !!Object.values(i).find((t => t && t.isRun)) }, run: function (n) { if (!o.OPTIONS.getModelOption(n).autoRotation || i[n] && i[n].isRun) return; i[n] && i[n].reserve && clearTimeout(i[n].reserve), i[n] && i[n].animation && cancelAnimationFrame(i[n].animation), i[n] = { isRun: !0, reserve: {}, animation: {} }; const s = this, r = o.modelGroup.getTargetObject(n), a = r.rotation.y; let l; function h(c) { if (null == l && (l = c), !s.isRunning()) return cancelAnimationFrame(i[n].animation), i[n].isRun = !1, s.duration = t, s.allowCanceled = e, void (o.userControl || o.setPositionRelay.isRunning() || o.active()); const d = g("easeOutSine", (c - l) / s.duration); if (r.rotation.y = p(a + 2 * Math.PI * d), d >= 1 || c - l >= s.duration || r.rotation.y >= a + 2 * Math.PI) return cancelAnimationFrame(i[n].animation), i[n].isRun = !1, s.duration = t, s.allowCanceled = e, r.rotation.y = p(a + 2 * Math.PI), void (o.userControl || o.setPositionRelay.isRunning() || o.active()); i[n].animation = requestAnimationFrame(h) } this.allowCanceled || o.inactive(), i[n].reserve = setTimeout((() => { cancelAnimationFrame(i[n].animation), i[n].animation = requestAnimationFrame(h) }), 600) }, cancel: function () { this.allowCanceled && o.userControl && (Object.values(i).forEach((t => { t.reserve.forEach((t => clearTimeout(t))), t.animation.forEach((t => clearTimeout(t))) })), i = {}, this.duration = t, this.allowCanceled = e) } } }(), this.setPositionRelay = function () { let t = {}; return { delay: 0, interval: 0, isRunning: function () { return !!Object.values(t).find((t => t && t.isRun)) }, set: function (e, i) { t[e] = { startPose: null, isRun: !1, actions: [], reserve: [], onRelayEnd: [] }, i && (i.actions && (t[e].actions = Object.entries(i.actions)), i.startPose && (t[e].startPose = i.startPose)) }, startPose: function (e) { if (!t[e]) return; const { startPose: i, actions: n } = t[e]; i && n && n != [] && 0 != n.length && i(e) }, run: function (e, i) { if (!t[e]) return; const { actions: n, onRelayEnd: s } = t[e]; "function" == typeof i && s.push(i), n != [] && 0 != n.length ? (t[e].isRun = !0, t[e].reserve.forEach((t => clearTimeout(t))), t[e].reserve = [], o.inactive(), n.forEach((([i, r], a) => { t[e].reserve[a] = setTimeout((() => { "function" == typeof r && r(), s.length > 0 && a == n.length - 1 && s.forEach((t => t())) }), parseInt(this.delay) + parseInt(i)) }))) : s.length > 0 && s.forEach((t => t())) }, clear: function () { this.delay = 0, this.interval = 0, Object.values(t).forEach((t => t.reserve.forEach((t => clearTimeout(t))))), t = {} }, cancel: function (e) { t[e] && (t[e].reserve.forEach((t => clearTimeout(t))), t[e].isRun = !1) } } }(), this.init() } init() { this.scene.add(this.modelGroup) } setModelData(t) { this.modelData = this.productData.getModelData(t), this.modelData.color = c(this.modelData.color, this.OPTIONS.colorchip, this.colorName), this.modelName = t, this.colorName = this.productData.getDefaultColorName(t), this.modelScale = this.modelData.scale || 100, this.OPTIONS.zoom && (this.initPosition.zoom = f(this.OPTIONS.zoom)), this.OPTIONS.x && (this.initPosition.angleY = this.OPTIONS.x), this.OPTIONS.y && (this.initPosition.angleX = this.OPTIONS.y), this.startPosition = this.OPTIONS.startPosition || this.initPosition.clone() } setViewerEncoding(t) { const e = t || this.modelName; "sRGB" == this.productData.getModelData(e)["output-rendering"] ? (this.renderer.toneMapping = 4, this.renderer.toneMappingExposure = 1.2, this.renderer.textureEncoding = At, this.renderer.outputEncoding = At) : (this.renderer.toneMapping = 0, this.renderer.toneMappingExposure = 1, this.renderer.textureEncoding = Tt, this.renderer.outputEncoding = Tt) } checkIsSample(t) { const e = "v3d-modelviewer--sample", i = "v3d-msg-smaple"; let n = this.container.querySelector(`.${i}`); t && !this.container.classList.contains(e) ? (this.container.classList.add(e), n ? setHiddenAttribute(n, !1) : (n = document.createElement("div"), n.classList.add(i), n.innerText = "Placeholder Model Sample Text", this.gltfObject.add(new CSS2DObject(n)))) : !t && this.container.classList.contains(e) && (this.container.classList.remove(e), setHiddenAttribute(n, !0)) } getFilePath(t, e) { const i = location.hostname; let n = t; for (let t in e) e[t].find((t => i.indexOf(t) > -1)) && (n = t); return n } async loadViewerModels() { this.viewer.stopRender(), this.removeModels(); const t = this.OPTIONS.modelOptionList, e = t.find((t => t.default)) || t[0]; this.defaultModelName = e.modelName, this.defaultColorName = e.color || this.productData.getDefaultColorName(this.defaultModelName), (await this.loadAllHDR(this.defaultModelName)).forEach((t => { "scene" === t.hdrType ? this.setHdrCache(t, t.hdrName, !0) : "model" === t.hdrType && this.setHdrCache(t, t.hdrName) })), this.isInit || (this.cameraControls = new Th(this.viewer.controls), this.positionControls = new Dh(this.viewer.controls), this.setLoadModelStatusBeforeInit()); for (const e of t) await this.loadByModelOption(e); this.update(), this.isInit || (this.isInit = !0) } async loadByModelOption(t) { const e = t.modelName, i = t.color || this.productData.getDefaultColorName(e), n = this.productData.getModelData(e); t.introPose && this.setPositionRelay.set(e, bh.call(this, n.statustoggle, t.introPose)), this.setModelData(e); const s = await this.loadModel(e, i); this.setViewerEncoding(); const r = await this.postProcessModel(s, i); this.addModel(r), this.changeColorActive(e) } async loadModel(t, e, i) { e = e || this.colorName; const n = this.productData.getColorData(t, e), s = this.modelData.isSample ? this.modelPathBackup : this.getFilePath(T, this.modelPathMath), r = this.OPTIONS.jp && n.glbJp || n.glb, a = i || s + (this.modelData.isSample ? L : this.modelName) + "/" + r, o = this.OPTIONS.getModelOption(t); if (Oh[a]) return this.isProductChange = !1, Oh[a]; this.isProductChange = !0; try { const t = await gh(a); return this.loadGltfObject(t, o, a) } catch (e) { const i = this.modelPathBackup + (this.modelData.isSample ? L : t) + "/" + r; try { const t = await gh(i); return this.loadGltfObject(t, o, i) } catch (t) { } } } loadGltfObject(t, e, i) { const n = new _h(e, this.modelData, t), s = e.modelName; return n.modelName = s, n.scale.set(this.modelScale, this.modelScale, this.modelScale), n.position.set(e.position.x, e.position.y, e.position.z), n.rotation.set(e.rotation.x, e.rotation.y, e.rotation.z), n.initPosition = new yh({ angleX: e.rotation.x, angleY: e.rotation.y, angleZ: e.rotation.z, zoom: E, poseX: e.position.x, poseY: e.position.y, poseZ: e.position.z, angleLimit: !1 }), n.initPosition0 = n.initPosition.clone(), n.positionController = new Ih(this.viewer.controls, n), void 0 !== t.animations && t.animations.map((t => { "status_toggle" === t.name && (n.mixer = new xh(t, n), n.mixer.clipAction(t).play(), n.mixer.type = this.productData.getModelData(s).statustoggle) })), n.statusToggle ? (n.statusToggle = !0, n.mixer && n.mixer.setTrack(1)) : (n.statusToggle = !1, n.mixer && n.mixer.setTrack(0)), Oh[i] = n, n } addModel(t) { this.removeModel(), t.viewerModel = this, this.modelGroup.add(t) } removeModels() { this.modelGroup.children = this.modelGroup.children.filter((t => "gltfObject" !== t.name)) } async loadHDR(t, e) { e = e || this.colorName; const i = this.productData.getColorData(t, e), n = this.getFilePath(T, this.modelPathMath), s = i.envtype; if (Nh[s]) return; const r = `${n}hdr/${this.productData.hdrPath[s]}`, a = `${this.modelPathBackup}hdr/${this.productData.hdrPath[s]}`; try { await gh(r).then((t => this.setHdrCache(t, s, !0))) } catch (t) { await gh(a).then((t => this.setHdrCache(t, s, !0))) } } async loadAllHDR(t) { const e = this.productData.getColorData(t, this.defaultColorName), i = this.getFilePath(T, this.modelPathMath), n = e.envtype, s = `${i}hdr/${this.productData.hdrPath[n]}`, r = `${this.modelPathBackup}hdr/${this.productData.hdrPath[n]}`, a = new Promise((async t => { let e; try { e = await gh(s) } catch (t) { e = await gh(r) } e.hdrType = "scene", e.hdrName = n, t(e) })), o = this.productData.getModelData(t), l = new Set, h = []; return o.color.forEach((t => { for (const e of t.envCustom) l.has(e.type) || l.add(e.type) })), l.forEach((t => { const e = new Promise((async e => { const i = this.productData.hdrPath[t], n = `${this.getFilePath(T, this.modelPathMath)}hdr/${i}`, s = `${this.modelPathBackup}hdr/${i}`; let r; try { r = await gh(n) } catch (t) { r = await gh(s) } r.hdrType = "model", r.hdrName = t, e(r) })); h.push(e) })), Promise.all([a].concat(h)) } async setCustomEnv(t, e) { e = e || this.colorName; const i = t.modelName, n = this.productData.getColorData(i, e).envCustom; if (null != n) { for (const e of n) { const i = this.productData.hdrPath[e.type]; if (null == i) continue; let n = {}; if (t.traverse((t => { t.isMesh && e.target.indexOf(t.material.name) > -1 && null == n[t.material.name] && (n[t.material.name] = t.material) })), Nh[e.type]) { for (let t in n) this.setEnvMapByCache(n[t], e.type); continue } const s = `${this.getFilePath(T, this.modelPathMath)}hdr/${i}`, r = `${this.modelPathBackup}hdr/${i}`; try { await gh(s).then((t => { for (let i in n) this.setHdrCache(t, e.type), this.setEnvMapByCache(n[i], e.type) })) } catch (t) { await gh(r).then((t => { for (let i in n) this.setHdrCache(t, e.type), this.setEnvMapByCache(n[i], e.type) })) } } return t } } async setCustomMaterial(t, e) { const i = t.modelName, n = this.productData.getColorData(i, e).custumMaterial; return n ? (await n.forEach((e => { let n = {}; t.traverse((t => { if (t.isMesh && e.target.indexOf(t.material.name) > -1 && null == n[t.material.name]) for (let n in e.options) if ("color" == n || "emissive" == n) { const i = new ae(e.options[n]); t.material[n] = i, "color" == n && (t.material.color0 = i) } else if ("renderOrder" == n) t[n] = e.options[n]; else if ("emissiveMap" != n && "alphaMap" != n && "map" != n && "metalnessMap" != n || null === e.options[n]) t.material[n] = e.options[n]; else { const s = Array.isArray(e.options[n]) ? e.options[n][0] : e.options[n], r = Array.isArray(e.options[n]) ? e.options[n][1] : null; gh(`${this.OPTIONS.assetsPath}models/${i}/${s}`).then((e => { if (e.src0 = s, e.options0 = r, e.flipY = t.material[n] && t.material[n].flipY, e.encoding = At, "alphaMap" == n && (t.material.transparent = !0), r) for (let t in r) "repeat" == t && r[t] && (e.wrapS = J, e.wrapT = J); t.material.needsUpdate = !0, t.material[n] = e })) } })) })), t) : t } setHdrCache(t, e, i = !1) { const n = new Qn(this.renderer); n.compileEquirectangularShader(), i && (n.far = 50, this.environmentHdrName = e); const s = n.fromEquirectangular(t).texture; s.hdrType = t.hdrType || "", s.hdrName = t.hdrName || "", Nh[e] = s, t.dispose(), n.dispose() } setEnvMapByCache(t, e) { t.envMap = Nh[e] } async changeColor(t, e) { if (!e) return; if (!this.productData.getColorData(t, e)) return; const i = { modelName: t, color: e }; this.modelGroup.getTargetObject(t) ? this.OPTIONS.setModelOption(t, i) : this.OPTIONS.setModelOptionList([i]), this.setModelData(t); const n = await this.loadModel(t, e); this.modelGroup.children[0].modelName === t && (n.statusToggle = this.modelGroup.children[0].statusToggle); const s = await this.postProcessModel(n, e); this.removeModels(), this.addModel(s) } async postProcessModel(t, e) { const i = t.modelName; return t.setScreenSync(this.modelData.statustoggle), this.scene.environment = Nh[this.environmentHdrName], this.colorName = e, !this.isProductChange && this.isInit || (this.changeProductActive(i), this.checkIsSample(this.modelData.isSample)), await this.setCustomEnv(t, e), await this.setCustomMaterial(t, e), t.screenUpdate(), t } changeColorActive(t) { const e = this.OPTIONS.getModelOption(t); this.modelGroup.getTargetObject(t).screenUpdate(), null === e.introPose || e.introPoseOnce && this.checkIntroPoseUsed(t) || this.setPositionRelay.startPose(t), e.introPose ? this.actionIntroPose(t) : (e.autoRotation && this.autoRotation.run(t), this.setLoadModelAfterActive()) } changeProductActive(t) { this.modelGroup.children.forEach((t => { const e = this.productData.getModelData(t.modelName); void 0 !== t.mixer && void 0 !== e.statustoggle && null !== t.mixer && (t.statusToggle ? (t.statusToggle = !0, t.mixer.setTrack(1)) : (t.statusToggle = !1, t.mixer.setTrack(0))) })) } actionIntroPose(t) { const e = this, i = this.modelGroup.getTargetObject(t), n = this.OPTIONS.getModelOption(t), s = bh.call(this, this.modelData.statustoggle, n.introPose); !s || !s.actions || n.introPoseOnce && this.checkIntroPoseUsed(t) ? (n.autoRotation && this.autoRotation.run(t), this.setLoadModelAfterActive()) : (this.inactive(), n.introPoseOnce || (this.setPositionRelay.enabled = !0), this.setPositionRelay.delay = n.introPoseHold ? 5e3 : 1e3, n.introPoseHold && !1 !== n.introPoseHoldLimit && (this.setPositionRelay.delay = 1e3 * n.introPoseHoldLimit), this.introPoseReady = !0, setTimeout((() => { const e = new CustomEvent("introPoseReady", { detail: { modelName: t } }); window.dispatchEvent(e) }), 100), this.setPositionRelay.run(t, (function () { n.introPoseOnce && !e.checkIntroPoseUsed(t) && e.setIntroPoseUsed(t), e.setPositionRelay.cancel(t); const s = e.getModelPosition(t); if (s && !i.initPosition.equals(s)) { function a(t) { const n = i.initPosition.clone(); n.angleLimit = !0, i.positionController.setPosition(n, 500, void 0, void 0, void 0, !0), e.cameraControls.reset(), e.container.removeEventListener("pointerdown", a), e.container.removeEventListener("touchstart", a), e.container.removeEventListener("wheel", a) } e.container.addEventListener("pointerdown", a), e.container.addEventListener("touchstart", a, { passive: !0 }), e.container.addEventListener("wheel", a, { passive: !0 }) } e.setLoadModelAfterActive(), e.introPoseEnd = !0; const r = new CustomEvent("introPoseEnd", { detail: { modelName: t } }); window.dispatchEvent(r) }))) } checkIntroPoseUsed(t) { return !!this.introPoseUsedData[t] } setIntroPoseUsed(t) { this.introPoseUsedData[t] = !0, o(R, JSON.stringify(this.introPoseUsedData)) } setLoadModelAfterActive() { !this.autoRotation.allowCanceled && this.autoRotation.isRunning() || this.setPositionRelay.isRunning() || this.active() } removeModel(t) { const e = this.modelGroup.getTargetObject(t); this.modelGroup.remove(e) } inactive(t = !0) { this.userControl = !1, this.viewer.controls.userControl = !1, t && this.autoRotation.cancel(), this.setPositionRelay.isRunning() && this.autoRotation.allowCanceled && !this.autoRotation.isRunning() && this.modelGroup.children.forEach((t => { this.statusToggleInactive(t.modelName, !0), this.setPositionRelay.clear(t.modelName) })) } active() { this.viewer.controls && (this.userControl = !0, this.viewer.controls.userControl = !0) } disable() { this.enabled = !1 } enable() { this.enabled = !0 } getModelPosition(t) { const e = this.modelGroup.getTargetObject(t); if (e) return new yh({ angleX: e.rotation.x, angleY: e.rotation.y, angleZ: e.rotation.z, poseX: e.position.x, poseY: e.position.y, poseZ: e.position.z, zoom: this.camera.position.z }) } setLoadModelStatusBeforeInit() { this.enable(), this.initPosition0 = this.initPosition.clone(), this.initPosition0.angleLimit = !1, this.setInitPosition() } setCanvasAltText(t) { this.renderer.domElement.setAttribute("aria-hidden", !0); const e = document.createElement("span"); e.className = "sr-only"; let i = t || ""; e.innerText = i; const n = this.renderer.domElement.parentElement.querySelector("span.sr-only"); n ? n.innerText != i && (n.innerText = i) : this.renderer.domElement.insertAdjacentElement("afterend", e) } statusToggleActive(t, e = !1) { if (!this.enabled && !e) return; if (!this.userControl && !e) return; const i = this.modelGroup.getTargetObject(t), n = this.productData.getModelData(t); i.statusToggle = !0, n.statustoggle && i && i.mixer && i.mixer.open(this.onMixerStart.bind(this), this.onMixerChange.bind(this), this.onMixerEnd.bind(this)) } statusToggleInactive(t, e = !1) { if (!this.enabled && !e) return; if (!this.userControl && !e) return; const i = this.modelGroup.getTargetObject(t), n = this.productData.getModelData(t); i.statusToggle = !1, n.statustoggle && i && i.mixer && i.mixer.close(this.onMixerStart.bind(this), this.onMixerChange.bind(this), this.onMixerEnd.bind(this)) } setInitPosition() { this.positionControls.setPosition(this.initPosition, 0) } setPosition(t, e, i, n, s, r = !1) { (this.enabled || r) && (this.userControl || r) && (this.modelGroup.children.forEach((t => { t.positionController && t.positionController.stop() })), this.autoRotation.cancel(), this.positionControls.setPosition(t, e, i, n, s, r)) } toggleActionSetTime(t, e = 1, i = 0, n = !1) { const s = this.modelGroup.getTargetObject(t); if (!t || !s) return; const r = s.mixer; null != r && (e = Math.min(Math.max(e, 0), 1), r.setTrack(e, i, void 0, this.onMixerChange.bind(this), void 0)) } screenUpdate() { this.modelGroup.children.forEach((t => { t.screenUpdate() })) } reset(t, e = !1) { this.enabled && (this.userControl || e) && (this.autoRotation.cancel(), this.initPosition0.angleLimit = !0, this.setPosition(this.initPosition0, void 0, void 0, t, void 0, !0), this.setPositionRelay.isRunning() && this.modelGroup.children.forEach((t => { this.statusToggleInactive(t.modelName, !0), this.setPositionRelay.cancel(t.modelNmae) })), this.cameraControls.isRun && this.cameraControls.reset()) } onPointerDown(t) { 1 == this.autoRotation.allowCanceled && this.autoRotation.cancel() } onPointerMove(t) { } onDoubleClick(t) { this.modelGroup.children.forEach((t => { !0 === t.statusToggle ? this.statusToggleInactive(t.modelName) : this.statusToggleActive(t.modelName) })) } onMixerStart() { this.isMixerRun = !0; const t = new CustomEvent("mixerStart"); window.dispatchEvent(t) } onMixerChange() { this.screenUpdate() } onMixerEnd() { this.isMixerRun = !1 } update() { this.positionControls && this.positionControls.update(), this.camera.updateProjectionMatrix(), this.viewer.render() } } class Fh { constructor(t, e) { this.backupPath = void 0 !== t.backupPath ? t.backupPath : "./assets/", this.assetsPath = void 0 !== t.assetsPath ? t.assetsPath : this.backupPath, this.bgcolor = void 0 !== t.bgcolor ? t.bgcolor : "F7F7F7", this.language = void 0 !== t.language ? t.language : null, this.jp = void 0 !== t.jp && t.jp, this.jpDomain = !!S.find((t => location.hostname.indexOf(t) > -1)), this.mode = void 0 !== t.mode ? t.mode : null, this.ar = void 0 === t.ar || t.ar, this.device = void 0 !== t.device ? t.device : null, this.devMode = void 0 !== t.devMode ? t.devMode : null, this.devModeOS = void 0 !== t.devModeOS ? t.devModeOS : null, this.exclusiveMode = void 0 !== t.exclusiveMode && t.exclusiveMode, this.useZoom = void 0 === t.useZoom || t.useZoom, this.usePan = void 0 === t.usePan || t.usePan, this.x = void 0 !== t.x ? u(t.x) : x, this.y = void 0 !== t.y ? u(t.y) : y, this.minAngleX = void 0 !== t.minAngleX ? u(t.minAngleX) : u(-180), this.minAngleY = void 0 !== t.minAngleY ? u(t.minAngleY) : u(-180), this.maxAngleX = void 0 !== t.maxAngleX ? u(t.maxAngleX) : u(180), this.maxAngleY = void 0 !== t.maxAngleY ? u(t.maxAngleY) : u(180), this.zoom = void 0 !== t.zoom ? t.zoom : 100, this.modelOptionList = [], this.setModelOptionList(e) } getModelOption(t) { return this.modelOptionList.find((e => e.modelName === t)) } setModelOption(t, e) { const i = this.modelOptionList.find((e => e.modelName === t)); for (const t in e) i[t] = e[t] } setModelOptionList(t) { this.modelOptionList = t.map((t => ({ modelName: void 0 !== t.modelName ? t.modelName : null, color: void 0 !== t.color ? t.color : null, autoRotation: void 0 !== t.autoRotation && t.autoRotation, screen: void 0 !== t.screen ? t.screen : 1, screenMode: void 0 !== t.screenMode ? t.screenMode : "normal", statusToggle: void 0 !== t.statusToggle ? t.statusToggle : 0, rotation: t.rotation ? { x: void 0 !== t.rotation.x ? t.rotation.x : x, y: void 0 !== t.rotation.y ? t.rotation.y : y, z: void 0 !== t.rotation.z ? t.rotation.z : b } : M, position: t.position ? { x: void 0 !== t.position.x ? t.position.x : x, y: void 0 !== t.position.y ? t.position.y : y, z: void 0 !== t.position.z ? t.position.z : b } : M, initPosition: t.initPosition ? new yh(t.initPosition) : null, introPose: void 0 !== t.introPose ? t.introPose : null, introPoseOnce: void 0 !== t.introPoseOnce && t.introPoseOnce, introPoseHold: void 0 !== t.introPoseHold && t.introPoseHold, introPoseHoldLimit: void 0 !== t.introPoseHoldLimit ? t.introPoseHoldLimit : 5 }))) } } const kh = []; class Uh { constructor(t, e) { this.OPTIONS = t, this.localData = e, this.color = null, this.defaultModelName = null, this.modelList = null, this.product = null, this.hdrPath = null, this.compare = null, this.compareAll = null } async loadViewerData() { const t = await this.loadKey(); await this.loadProductData(t) } async loadKey() { const t = this; let e = [`${this.OPTIONS.assetsPath}product/key.json?${(new Date).getTime()}`]; return await Promise.all(e.map((t => _(t)))).then((e => (this.hdrPath = e[0].hdr, this.compare = this.localData && this.localData.compare ? this.localData.compare : null, this.compareAll = e[0].compare, this.defaultModelName = this.OPTIONS.modelOptionList[0].modelName ? function (e) { if (t.compareAll.indexOf(e) > -1) return e; let i = e; return t.compareAll.includes(i) || (i.includes("-5g") ? i = i.replace("-5g", "") : i += "-5g"), t.compareAll.includes(i) ? i : e }(this.OPTIONS.modelOptionList[0].modelName) : "galaxy-sample", this.modelList = this.localData && this.localData.models ? this.localData.models : this.compareAll, this.product = {}, this.modelList && -1 == this.modelList.indexOf(this.defaultModelName) && this.defaultModelName && this.isSampleDataMatch(this.defaultModelName) && this.modelList.unshift(this.defaultModelName), e))) } async loadProductData() { let t = [this.defaultModelName]; this.modelList && (t = t.concat(this.modelList)), t = [...new Set(t)]; const e = this.compareAll.filter((e => !t.includes(e))); for (let t = 0; t _(t)))).then((t => { if (Object.assign(this.product, ...t), this.localData) for (let t in this.product) this.localData[t] && this.localData[t].color && (this.product[t].color = c(this.product[t].color, this.localData[t].color, this.localData[t].defaultColor)); return t })) } getModelsURL() { let t = this.OPTIONS.modelOptionList.map((t => t.modelName)), e = []; this.modelList && (t = t.concat(this.modelList)), t = [...new Set(t)]; for (let i = 0; i 21 && t.includes("ultra") && (i.statustoggle = "s-pen"); break; case "galaxy-note": i.statustoggle = "s-pen"; break; case "galaxy-z-fold": i.statustoggle = "fold"; break; case "galaxy-z-flip": i.statustoggle = "flip" }let n = this.localData[t].color; return i.color = n.map(((t, e) => ({ key: t, text: t, default: 0 == e, compression: !0, glb: i.statustoggle ? D[i.statustoggle] : D.bar, envtype: "envSRGBPhantom" }))), i } getModelData(t) { return this.product[t] } getDefaultModelName() { return this.defaultModelName } getDefaultColorName(t) { return this.getModelData(t).color.find((t => t.default)).key } getColorData(t, e) { return this.getModelData(t).color.find((t => t.key == e)) } getExclusiveColorNameList(t) { return this.getModelData(t).color.filter((t => t.exclusive)).map((t => t.key)) } } const Bh = new qe, Vh = new Cn, Gh = Math.cos(70 * Wt.DEG2RAD), Hh = new _e, jh = 2 * Math.PI, Wh = -1, Xh = 1e-6; class Yh { constructor(t, e, i, n = null) { this.OPTIONS = t, this.object = e, this.domElement = n, this.productObject = i, this.state = Wh, this.enabled = !0, this.userControl = !1, this.isPositioning = !1, this.target = new _e, this.cursor = new _e, this.minDistance = 100 * E / P, this.maxDistance = 100 * E / C, this.minZoom = 0, this.maxZoom = 1 / 0, this.minTargetRadius = 0, this.maxTargetRadius = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !0, this.dampingFactor = .05, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = .4, this.enablePan = !0, this.panSpeed = 1, this.screenSpacePanning = !0, this.keyPanSpeed = 7, this.zoomToCursor = !1, this.autoRotate = !1, this.autoRotateSpeed = 2, this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }, this.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }, this.touches = { ONE: 0, TWO: 2 }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this.productOriginAngle = new _e, this._domElementKeyEvents = null, this._lastPosition = new _e, this._lastRotation = new _e, this._lastQuaternion = new ve, this._lastTargetPosition = new _e, this._quat = (new ve).setFromUnitVectors(e.up, new _e(0, 1, 0)), this._quatInverse = this._quat.clone().invert(), this._spherical = new jo, this._sphericalDelta = new jo, this._scale = 1, this._panOffset = new _e, this._rotateStart = new Xt, this._rotateEnd = new Xt, this._rotateDelta = new Xt, this._rotatePrev = new Xt(this.productObject.rotation.x, this.productObject.rotation.y), this._panStart = new Xt, this._panEnd = new Xt, this._panDelta = new Xt, this._dollyStart = new Xt, this._dollyEnd = new Xt, this._dollyDelta = new Xt, this._positionStart = new Xt, this._positionEnd = new Xt, this._positionDelta = new Xt, this._zoomStart = new Xt, this._zoomEnd = new Xt, this._zoomDelta = .1, this._setPositionSpeed = 1, this._dollyDirection = new _e, this._mouse = new Xt, this._performCursorZoom = !1, this._pointers = [], this._pointerPositions = {}, this._controlActive = !1, this._onPointerMove = Zh.bind(this), this._onPointerDown = qh.bind(this), this._onPointerUp = $h.bind(this), this._onContextMenu = rc.bind(this), this._onKeyDown = ec.bind(this), this._onTouchStart = ic.bind(this), this._onTouchMove = nc.bind(this), this._onTouchEnd = sc.bind(this), this._onMouseDown = Kh.bind(this), this._onMouseMove = Jh.bind(this), this._onMouseUp = Qh.bind(this), this._onMouseWheel = tc.bind(this), this._interceptControlDown = ac.bind(this), this._interceptControlUp = oc.bind(this), this.setPositionControls = null, this.setPositionController = { list: [], isRun: !1, update: function () { this.list.forEach((t => { t.update() })), this.list.find((t => t.isRun)) ? this.isRun = !0 : this.isRun = !1 } }, this.cameraControls = null, null !== this.domElement && this.connect(), this.update() } setPositionStop() { this._rotateDelta.set(0, 0), this.setPositionSync() } setPositionSync() { this._rotateEnd.set(this.productObject.rotation.x, this.productObject.rotation.y), this._rotatePrev.set(this.productObject.rotation.x, this.productObject.rotation.y), this._positionEnd.set(this.productObject.position.x, this.productObject.position.y), this._rotateStart.copy(this._rotateEnd), this._positionStart.copy(this._positionEnd) } connect() { this.domElement.addEventListener("contextmenu", this._onContextMenu), this.domElement.addEventListener("pointerdown", this._onPointerDown), this.domElement.addEventListener("wheel", this._onMouseWheel, { passive: !0 }), this.domElement.addEventListener("touchstart", this._onTouchStart), this.domElement.getRootNode().addEventListener("keydown", this._interceptControlDown, { passive: !0, capture: !0 }) } disconnect() { this.domElement.removeEventListener("contextmenu", this._onContextMenu), this.domElement.removeEventListener("pointerdown", this._onPointerDown), this.domElement.removeEventListener("wheel", this._onMouseWheel), this.domElement.removeEventListener("touchstart", this._onTouchStart), this.domElement.removeEventListener("touchend", this._onTouchEnd), this.domElement.removeEventListener("touchmove", this._onTouchMove), this.domElement.removeEventListener("pointermove", this._onPointerMove), this.domElement.removeEventListener("pointerup", this._onPointerUp), this.domElement.removeEventListener("pointerleave", this._onPointerUp), this.stopListenToKeyEvents(), this.domElement.getRootNode().removeEventListener("keydown", this._interceptControlDown, { capture: !0 }) } dispose() { this.disconnect() } getPolarAngle() { return this._spherical.phi } getAzimuthalAngle() { return this._spherical.theta } getDistance() { return this.object.position.distanceTo(this.target) } listenToKeyEvents(t) { t.addEventListener("keydown", this._onKeyDown), this._domElementKeyEvents = t } stopListenToKeyEvents() { null !== this._domElementKeyEvents && (this._domElementKeyEvents.removeEventListener("keydown", this._onKeyDown), this._domElementKeyEvents = null) } saveState() { this.target0.copy(this.target), this.position0.copy(this.object.position), this.zoom0 = this.object.zoom } reset() { this.target.copy(this.target0), this.object.position.copy(this.position0), this.object.zoom = this.zoom0, this.object.updateProjectionMatrix(), this.update(), this.state = Wh } setPosition(t, e = 1, i) { const n = null == (t = t || {}).angleX ? this.productObject.rotation.x : t.angleX, s = null == t.angleY ? this.productObject.rotation.y : t.angleY, r = null == t.zoom ? this.object.position.z : t.zoom, a = null == t.panX ? this.object.position.x : t.panX, o = null == t.panY ? this.object.position.y : t.panY; if (0 == e) return this._rotateUp(n - this.productObject.rotation.x), this._rotateLeft(s - this.productObject.rotation.y), this.object.position.z = r, this.object.position.x = a, this.object.position.y = o, this.target.x = a, void (this.target.y = o); state = 8, this._setPositionSpeed = e, zoomStart = this.object.position.z, zoomEnd = Math.max(Math.min(r, this.maxDistance), this.minDistance), zoomDelta = .3 * this.dampingFactor * this._setPositionSpeed, this._rotateStart.set(this.productObject.rotation.x, this.productObject.rotation.y), this._rotateEnd.set(n, s), this._rotateDelta.set(this.dampingFactor * this.rotateSpeed * this._setPositionSpeed, this.dampingFactor * this.rotateSpeed * this._setPositionSpeed), this._positionStart.set(this.object.position.x, this.object.position.y), this._positionEnd.set(a, o), this._positionDelta.set(this.dampingFactor, this.dampingFactor) } setPositionStart() { this.state = 8 } update(t = null) { const e = this.object.position; Hh.copy(e).sub(this.target), Hh.applyQuaternion(this._quat), this._spherical.setFromVector3(Hh), this.autoRotate && this.state === Wh && this._rotateLeft(this._getAutoRotationAngle(t)), this.enableDamping && 8 !== this.state && 0 !== this.state ? (this._spherical.theta += this._sphericalDelta.theta * this.dampingFactor, this._spherical.phi += this._sphericalDelta.phi * this.dampingFactor, this._rotateDelta.length() > .01 && (this._rotateLeft(this._rotateDelta.x * this.dampingFactor * .08), this._rotateUp(this._rotateDelta.y * this.dampingFactor * .08))) : 8 !== this.state && (this._spherical.theta += this._sphericalDelta.theta, this._spherical.phi += this._sphericalDelta.phi); let i = this.minAzimuthAngle, n = this.maxAzimuthAngle; isFinite(i) && isFinite(n) && (i Math.PI && (i -= jh), n Math.PI && (n -= jh), this._spherical.theta = i (i + n) / 2 ? Math.max(i, this._spherical.theta) : Math.min(n, this._spherical.theta)), this._spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this._spherical.phi)), this._spherical.makeSafe(), !0 === this.enableDamping && 8 !== this.state ? this.target.addScaledVector(this._panOffset, this.dampingFactor) : 8 !== this.state && this.target.add(this._panOffset), this.target.sub(this.cursor), this.target.clampLength(this.minTargetRadius, this.maxTargetRadius), this.target.add(this.cursor); let s = !1; if (this.zoomToCursor && this._performCursorZoom || this.object.isOrthographicCamera) this._spherical.radius = this._clampDistance(this._spherical.radius); else { const t = this._spherical.radius; this._spherical.radius = this._clampDistance(this._spherical.radius * this._scale), s = t != this._spherical.radius } if (Hh.setFromSpherical(this._spherical), Hh.applyQuaternion(this._quatInverse), e.copy(this.target).add(Hh), this.cameraControls && this.cameraControls.isRun && this.cameraControls.update(), this.object.lookAt(this.target), !0 === this.enableDamping && 8 !== this.state ? (this._sphericalDelta.theta *= 1 - this.dampingFactor, this._sphericalDelta.phi *= 1 - this.dampingFactor, this._rotateDelta.x *= 1 - this.dampingFactor, this._rotateDelta.y *= 1 - this.dampingFactor, this._panOffset.multiplyScalar(1 - this.dampingFactor)) : 8 !== this.state && (this._sphericalDelta.set(0, 0, 0), this._rotateDelta.set(0, 0), this._panOffset.set(0, 0, 0)), 8 == this.state && (this.setPositionControls.update(), this.setPositionController.update(), this.setPositionControls.isRun || this.setPositionController.isRun || (this.state = Wh, this.isPositioning = !1, this._sphericalDelta.set(0, 0, 0), this._panOffset.set(0, 0, 0), this._rotateDelta.set(0, 0), this._zoomStart = this._zoomEnd, this.setPositionSync())), this.zoomToCursor && this._performCursorZoom) { let t = null; if (this.object.isPerspectiveCamera) { const e = Hh.length(); t = this._clampDistance(e * this._scale); const i = e - t; this.object.position.addScaledVector(this._dollyDirection, i), this.object.updateMatrixWorld(), s = !!i } else if (this.object.isOrthographicCamera) { const e = new _e(this._mouse.x, this._mouse.y, 0); e.unproject(this.object); const i = this.object.zoom; this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom / this._scale)), this.object.updateProjectionMatrix(), s = i !== this.object.zoom; const n = new _e(this._mouse.x, this._mouse.y, 0); n.unproject(this.object), this.object.position.sub(n).add(e), this.object.updateMatrixWorld(), t = Hh.length() } else this.zoomToCursor = !1; null !== t && (this.screenSpacePanning ? this.target.set(0, 0, -1).transformDirection(this.object.matrix).multiplyScalar(t).add(this.object.position) : (Bh.origin.copy(this.object.position), Bh.direction.set(0, 0, -1).transformDirection(this.object.matrix), Math.abs(this.object.up.dot(Bh.direction)) Xh || this._lastRotation.distanceToSquared(this.object.rotation) > Xh || 8 * (1 - this._lastQuaternion.dot(this.object.quaternion)) > Xh || this._lastTargetPosition.distanceToSquared(this.target) > Xh) && (8 !== this.state && 1 == this.isPositioning && (this.isPositioning = !1), this._lastPosition.copy(this.object.position), this._lastRotation.copy(this.object.rotation), this._lastQuaternion.copy(this.object.quaternion), this._lastTargetPosition.copy(this.target), s = !1, !0) } _getAutoRotationAngle(t) { return null !== t ? jh / 60 * this.autoRotateSpeed * t : jh / 60 / 60 * this.autoRotateSpeed } _getZoomScale() { return Math.pow(.95, this.zoomSpeed) } _rotateLeft(t) { this._rotatePrev.y = p(this._rotatePrev.y + t), this._rotatePrev.y > 0 ? this._rotatePrev.y = Math.min(this.OPTIONS.maxAngleX, this._rotatePrev.y) : this._rotatePrev.y 0 ? this.productObject.rotation.x = Math.min(this.OPTIONS.maxAngleY, this.productObject.rotation.x) : this.productObject.rotation.x 0 ? this._dollyOut(this._getZoomScale()) : this._dollyDelta.y 0 && this._dollyOut(this._getZoomScale()), this.update() } _handleKeyDown(t) { let e = !1; switch (t.code) { case this.keys.UP: t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateUp(jh * this.rotateSpeed / this.domElement.clientHeight) : this._pan(0, this.keyPanSpeed), e = !0; break; case this.keys.BOTTOM: t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateUp(-jh * this.rotateSpeed / this.domElement.clientHeight) : this._pan(0, -this.keyPanSpeed), e = !0; break; case this.keys.LEFT: t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateLeft(jh * this.rotateSpeed / this.domElement.clientHeight) : this._pan(this.keyPanSpeed, 0), e = !0; break; case this.keys.RIGHT: t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateLeft(-jh * this.rotateSpeed / this.domElement.clientHeight) : this._pan(-this.keyPanSpeed, 0), e = !0 }e && (t.preventDefault(), this.update()) } _handleTouchStartRotate(t) { if (1 == t.touches.length) this._rotateStart.set(t.touches[0].pageX, t.touches[0].pageY); else { const e = .5 * (t.touches[0].pageX + t.touches[1].pageX), i = .5 * (t.touches[0].pageY + t.touches[1].pageY); this._rotateStart.set(e, i) } } _handleTouchStartPan(t) { if (1 == t.touches.length) this._panStart.set(t.touches[0].pageX, t.touches[0].pageY); else { const e = .5 * (t.touches[0].pageX + t.touches[1].pageX), i = .5 * (t.touches[0].pageY + t.touches[1].pageY); this._panStart.set(e, i) } } _handleTouchStartDolly(t) { const e = t.touches[0].pageX - t.touches[1].pageX, i = t.touches[0].pageY - t.touches[1].pageY, n = Math.sqrt(e * e + i * i); this._dollyStart.set(0, n) } _handleTouchStartDollyPan(t) { this.enableZoom && this._handleTouchStartDolly(t), this.enablePan && this._handleTouchStartPan(t) } _handleTouchStartDollyRotate(t) { this.enableZoom && this._handleTouchStartDolly(t), this.enableRotate && this._handleTouchStartRotate(t) } _handleTouchMoveRotate(t) { if (1 == t.touches.length) this._rotateEnd.set(t.touches[0].pageX, t.touches[0].pageY); else { const e = .5 * (t.touches[0].pageX + t.touches[1].pageX), i = .5 * (t.touches[0].pageY + t.touches[1].pageY); this._rotateEnd.set(e, i) } this._rotateDelta.subVectors(this._rotateEnd, this._rotateStart).multiplyScalar(this.rotateSpeed); const e = this.domElement; this._rotateLeft(jh * this._rotateDelta.x / e.clientHeight), this._rotateUp(jh * this._rotateDelta.y / e.clientHeight), this._rotateStart.copy(this._rotateEnd) } _handleTouchMovePan(t) { if (1 == t.touches.length) this._panEnd.set(t.touches[0].pageX, t.touches[0].pageY); else { const e = .5 * (t.touches[0].pageX + t.touches[1].pageX), i = .5 * (t.touches[0].pageY + t.touches[1].pageY); this._panEnd.set(e, i) } this._panDelta.subVectors(this._panEnd, this._panStart).multiplyScalar(this.panSpeed), this._pan(this._panDelta.x, this._panDelta.y), this._panStart.copy(this._panEnd) } _handleTouchMoveDolly(t) { const e = t.touches[0].pageX - t.touches[1].pageX, i = t.touches[0].pageY - t.touches[1].pageY, n = Math.sqrt(e * e + i * i); this._dollyEnd.set(0, n), this._dollyDelta.set(0, Math.pow(this._dollyEnd.y / this._dollyStart.y, this.zoomSpeed)), this._dollyOut(this._dollyDelta.y), this._dollyStart.copy(this._dollyEnd) } _handleTouchMoveDollyPan(t) { this.enableZoom && this._handleTouchMoveDolly(t), this.enablePan && this._handleTouchMovePan(t) } _handleTouchMoveDollyRotate(t) { this.enableZoom && this._handleTouchMoveDolly(t), this.enableRotate && this._handleTouchMoveRotate(t) } _addPointer(t) { this._pointers.push(t.pointerId) } _removePointer(t) { delete this._pointerPositions[t.pointerId]; for (let e = 0; e 50 && 0 == t.button && this.onDoubleClick(t), this.lastPointerUpTime = e } onDoubleClick(t) { this.viewer.onDoubleClick(t) } onHashChange(t) { } onReciveMessage(t) { } } /** * lil-gui * https://lil-gui.georgealways.com * @version 0.16.0 * @author George Michael Brower * @license MIT **/ class hc { constructor(t, e, i, n, s = "div") { this.parent = t, this.object = e, this.property = i, this._disabled = !1, this.initialValue = this.getValue(), this.domElement = document.createElement("div"), this.domElement.classList.add("controller"), this.domElement.classList.add(n), this.$name = document.createElement("div"), this.$name.classList.add("name"), hc.nextNameID = hc.nextNameID || 0, this.$name.id = "lil-gui-name-" + ++hc.nextNameID, this.$widget = document.createElement(s), this.$widget.classList.add("widget"), this.$disable = this.$widget, this.domElement.appendChild(this.$name), this.domElement.appendChild(this.$widget), this.parent.children.push(this), this.parent.controllers.push(this), this.parent.$children.appendChild(this.domElement), this._listenCallback = this._listenCallback.bind(this), this.name(i) } name(t) { return this._name = t, this.$name.innerHTML = t, this } onChange(t) { return this._onChange = t, this } _callOnChange() { this.parent._callOnChange(this), void 0 !== this._onChange && this._onChange.call(this, this.getValue()), this._changed = !0 } onFinishChange(t) { return this._onFinishChange = t, this } _callOnFinishChange() { this._changed && (this.parent._callOnFinishChange(this), void 0 !== this._onFinishChange && this._onFinishChange.call(this, this.getValue())), this._changed = !1 } reset() { return this.setValue(this.initialValue), this._callOnFinishChange(), this } enable(t = !0) { return this.disable(!t) } disable(t = !0) { return t === this._disabled || (this._disabled = t, this.domElement.classList.toggle("disabled", t), this.$disable.toggleAttribute("disabled", t)), this } options(t) { const e = this.parent.add(this.object, this.property, t); return e.name(this._name), this.destroy(), e } min(t) { return this } max(t) { return this } step(t) { return this } listen(t = !0) { return this._listening = t, void 0 !== this._listenCallbackID && (cancelAnimationFrame(this._listenCallbackID), this._listenCallbackID = void 0), this._listening && this._listenCallback(), this } _listenCallback() { this._listenCallbackID = requestAnimationFrame(this._listenCallback), this.updateDisplay() } getValue() { return this.object[this.property] } setValue(t) { return this.object[this.property] = t, this._callOnChange(), this.updateDisplay(), this } updateDisplay() { return this } load(t) { return this.setValue(t), this._callOnFinishChange(), this } save() { return this.getValue() } destroy() { this.parent.children.splice(this.parent.children.indexOf(this), 1), this.parent.controllers.splice(this.parent.controllers.indexOf(this), 1), this.parent.$children.removeChild(this.domElement) } } class cc extends hc { constructor(t, e, i) { super(t, e, i, "boolean", "label"), this.$input = document.createElement("input"), this.$input.setAttribute("type", "checkbox"), this.$input.setAttribute("aria-labelledby", this.$name.id), this.$widget.appendChild(this.$input), this.$input.addEventListener("change", (() => { this.setValue(this.$input.checked), this._callOnFinishChange() })), this.$disable = this.$input, this.updateDisplay() } updateDisplay() { return this.$input.checked = this.getValue(), this } } function dc(t) { let e, i; return (e = t.match(/(#|0x)?([a-f0-9]{6})/i)) ? i = e[2] : (e = t.match(/rgb\(\s*(\d*)\s*,\s*(\d*)\s*,\s*(\d*)\s*\)/)) ? i = parseInt(e[1]).toString(16).padStart(2, 0) + parseInt(e[2]).toString(16).padStart(2, 0) + parseInt(e[3]).toString(16).padStart(2, 0) : (e = t.match(/^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i)) && (i = e[1] + e[1] + e[2] + e[2] + e[3] + e[3]), !!i && "#" + i } const uc = { isPrimitive: !0, match: t => "string" == typeof t, fromHexString: dc, toHexString: dc }, pc = { isPrimitive: !0, match: t => "number" == typeof t, fromHexString: t => parseInt(t.substring(1), 16), toHexString: t => "#" + t.toString(16).padStart(6, 0) }, mc = { isPrimitive: !1, match: Array.isArray, fromHexString(t, e, i = 1) { const n = pc.fromHexString(t); e[0] = (n >> 16 & 255) / 255 * i, e[1] = (n >> 8 & 255) / 255 * i, e[2] = (255 & n) / 255 * i }, toHexString: ([t, e, i], n = 1) => pc.toHexString(t * (n = 255 / n) Object(t) === t, fromHexString(t, e, i = 1) { const n = pc.fromHexString(t); e.r = (n >> 16 & 255) / 255 * i, e.g = (n >> 8 & 255) / 255 * i, e.b = (255 & n) / 255 * i }, toHexString: ({ r: t, g: e, b: i }, n = 1) => pc.toHexString(t * (n = 255 / n) t.match(s)))), this._rgbScale = n, this._initialValueHexString = this.save(), this._textFocused = !1, this.$input.addEventListener("input", (() => { this._setValueFromHexString(this.$input.value) })), this.$input.addEventListener("blur", (() => { this._callOnFinishChange() })), this.$text.addEventListener("input", (() => { const t = dc(this.$text.value); t && this._setValueFromHexString(t) })), this.$text.addEventListener("focus", (() => { this._textFocused = !0, this.$text.select() })), this.$text.addEventListener("blur", (() => { this._textFocused = !1, this.updateDisplay(), this._callOnFinishChange() })), this.$disable = this.$text, this.updateDisplay() } reset() { return this._setValueFromHexString(this._initialValueHexString), this } _setValueFromHexString(t) { if (this._format.isPrimitive) { const e = this._format.fromHexString(t); this.setValue(e) } else this._format.fromHexString(t, this.getValue(), this._rgbScale), this._callOnChange(), this.updateDisplay() } save() { return this._format.toHexString(this.getValue(), this._rgbScale) } load(t) { return this._setValueFromHexString(t), this._callOnFinishChange(), this } updateDisplay() { return this.$input.value = this._format.toHexString(this.getValue(), this._rgbScale), this._textFocused || (this.$text.value = this.$input.value.substring(1)), this.$display.style.backgroundColor = this.$input.value, this } } class _c extends hc { constructor(t, e, i) { super(t, e, i, "function"), this.$button = document.createElement("button"), this.$button.appendChild(this.$name), this.$widget.appendChild(this.$button), this.$button.addEventListener("click", (t => { t.preventDefault(), this.getValue().call(this.object) })), this.$button.addEventListener("touchstart", (() => { })), this.$disable = this.$button } } class xc extends hc { constructor(t, e, i, n, s, r) { super(t, e, i, "number"), this._initInput(), this.min(n), this.max(s); const a = void 0 !== r; this.step(a ? r : this._getImplicitStep(), a), this.updateDisplay() } min(t) { return this._min = t, this._onUpdateMinMax(), this } max(t) { return this._max = t, this._onUpdateMinMax(), this } step(t, e = !0) { return this._step = t, this._stepExplicit = e, this } updateDisplay() { const t = this.getValue(); if (this._hasSlider) { let e = (t - this._min) / (this._max - this._min); e = Math.max(0, Math.min(e, 1)), this.$fill.style.width = 100 * e + "%" } return this._inputFocused || (this.$input.value = t), this } _initInput() { this.$input = document.createElement("input"), this.$input.setAttribute("type", "number"), this.$input.setAttribute("step", "any"), this.$input.setAttribute("aria-labelledby", this.$name.id), this.$widget.appendChild(this.$input), this.$disable = this.$input; const t = t => { const e = parseFloat(this.$input.value); isNaN(e) || (this._snapClampSetValue(e + t), this.$input.value = this.getValue()) }; let e, i, n, s, r, a = !1; const o = t => { if (a) { const n = t.clientX - e, s = t.clientY - i; Math.abs(s) > 5 ? (t.preventDefault(), this.$input.blur(), a = !1, this._setDraggingStyle(!0, "vertical")) : Math.abs(n) > 5 && l() } if (!a) { const e = t.clientY - n; r -= e * this._step * this._arrowKeyMultiplier(t), s + r > this._max ? r = this._max - s : s + r { this._setDraggingStyle(!1, "vertical"), this._callOnFinishChange(), window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", l) }; this.$input.addEventListener("input", (() => { const t = parseFloat(this.$input.value); isNaN(t) || this.setValue(this._clamp(t)) })), this.$input.addEventListener("keydown", (e => { "Enter" === e.code && this.$input.blur(), "ArrowUp" === e.code && (e.preventDefault(), t(this._step * this._arrowKeyMultiplier(e))), "ArrowDown" === e.code && (e.preventDefault(), t(this._step * this._arrowKeyMultiplier(e) * -1)) })), this.$input.addEventListener("wheel", (e => { this._inputFocused && (e.preventDefault(), t(this._step * this._normalizeMouseWheel(e))) })), this.$input.addEventListener("mousedown", (t => { e = t.clientX, i = n = t.clientY, a = !0, s = this.getValue(), r = 0, window.addEventListener("mousemove", o), window.addEventListener("mouseup", l) })), this.$input.addEventListener("focus", (() => { this._inputFocused = !0 })), this.$input.addEventListener("blur", (() => { this._inputFocused = !1, this.updateDisplay(), this._callOnFinishChange() })) } _initSlider() { this._hasSlider = !0, this.$slider = document.createElement("div"), this.$slider.classList.add("slider"), this.$fill = document.createElement("div"), this.$fill.classList.add("fill"), this.$slider.appendChild(this.$fill), this.$widget.insertBefore(this.$slider, this.$input), this.domElement.classList.add("hasSlider"); const t = t => { const e = this.$slider.getBoundingClientRect(); let i = (n = t, s = e.left, r = e.right, a = this._min, (n - s) / (r - s) * (this._max - a) + a); var n, s, r, a; this._snapClampSetValue(i) }, e = e => { t(e.clientX) }, i = () => { this._callOnFinishChange(), this._setDraggingStyle(!1), window.removeEventListener("mousemove", e), window.removeEventListener("mouseup", i) }; let n, s, r = !1; const a = e => { e.preventDefault(), this._setDraggingStyle(!0), t(e.touches[0].clientX), r = !1 }, o = e => { if (r) { const t = e.touches[0].clientX - n, i = e.touches[0].clientY - s; Math.abs(t) > Math.abs(i) ? a(e) : (window.removeEventListener("touchmove", o), window.removeEventListener("touchend", l)) } else e.preventDefault(), t(e.touches[0].clientX) }, l = () => { this._callOnFinishChange(), this._setDraggingStyle(!1), window.removeEventListener("touchmove", o), window.removeEventListener("touchend", l) }, h = this._callOnFinishChange.bind(this); let c; this.$slider.addEventListener("mousedown", (n => { this._setDraggingStyle(!0), t(n.clientX), window.addEventListener("mousemove", e), window.addEventListener("mouseup", i) })), this.$slider.addEventListener("touchstart", (t => { t.touches.length > 1 || (this._hasScrollBar ? (n = t.touches[0].clientX, s = t.touches[0].clientY, r = !0) : a(t), window.addEventListener("touchmove", o), window.addEventListener("touchend", l)) })), this.$slider.addEventListener("wheel", (t => { if (Math.abs(t.deltaX) this._max && (t = this._max), t } _snapClampSetValue(t) { this.setValue(this._clamp(this._snap(t))) } get _hasScrollBar() { const t = this.parent.root.$children; return t.scrollHeight > t.clientHeight } get _hasMin() { return void 0 !== this._min } get _hasMax() { return void 0 !== this._max } } class yc extends hc { constructor(t, e, i, n) { super(t, e, i, "option"), this.$select = document.createElement("select"), this.$select.setAttribute("aria-labelledby", this.$name.id), this.$display = document.createElement("div"), this.$display.classList.add("display"), this._values = Array.isArray(n) ? n : Object.values(n), this._names = Array.isArray(n) ? n : Object.keys(n), this._names.forEach((t => { const e = document.createElement("option"); e.innerHTML = t, this.$select.appendChild(e) })), this.$select.addEventListener("change", (() => { this.setValue(this._values[this.$select.selectedIndex]), this._callOnFinishChange() })), this.$select.addEventListener("focus", (() => { this.$display.classList.add("focus") })), this.$select.addEventListener("blur", (() => { this.$display.classList.remove("focus") })), this.$widget.appendChild(this.$select), this.$widget.appendChild(this.$display), this.$disable = this.$select, this.updateDisplay() } updateDisplay() { const t = this.getValue(), e = this._values.indexOf(t); return this.$select.selectedIndex = e, this.$display.innerHTML = -1 === e ? t : this._names[e], this } } class bc extends hc { constructor(t, e, i) { super(t, e, i, "string"), this.$input = document.createElement("input"), this.$input.setAttribute("type", "text"), this.$input.setAttribute("aria-labelledby", this.$name.id), this.$input.addEventListener("input", (() => { this.setValue(this.$input.value) })), this.$input.addEventListener("keydown", (t => { "Enter" === t.code && this.$input.blur() })), this.$input.addEventListener("blur", (() => { this._callOnFinishChange() })), this.$widget.appendChild(this.$input), this.$disable = this.$input, this.updateDisplay() } updateDisplay() { return this.$input.value = this.getValue(), this } } let Mc, wc, Sc, Tc = !1; class Ac { constructor({ parent: t, autoPlace: e = void 0 === t, container: i, width: n, title: s = "Controls", injectStyles: r = !0, touchStyles: a = !0 } = {}) { if (this.parent = t, this.root = t ? t.root : this, this.children = [], this.controllers = [], this.folders = [], this._closed = !1, this._hidden = !1, this.domElement = document.createElement("div"), this.domElement.classList.add("lil-gui"), this.$title = document.createElement("div"), this.$title.classList.add("title"), this.$title.setAttribute("role", "button"), this.$title.setAttribute("aria-expanded", !0), this.$title.setAttribute("tabindex", 0), this.$title.addEventListener("click", (() => this.openAnimated(this._closed))), this.$title.addEventListener("keydown", (t => { "Enter" !== t.code && "Space" !== t.code || (t.preventDefault(), this.$title.click()) })), this.$title.addEventListener("touchstart", (() => { })), this.$children = document.createElement("div"), this.$children.classList.add("children"), this.domElement.appendChild(this.$title), this.domElement.appendChild(this.$children), this.title(s), a && this.domElement.classList.add("allow-touch-styles"), this.parent) return this.parent.children.push(this), this.parent.folders.push(this), void this.parent.$children.appendChild(this.domElement); this.domElement.classList.add("root"), !Tc && r && (function () { const t = document.createElement("style"); t.innerHTML = '.lil-gui{--background-color:#1f1f1f;--text-color:#ebebeb;--title-background-color:#111;--title-text-color:#ebebeb;--widget-color:#424242;--hover-color:#4f4f4f;--focus-color:#595959;--number-color:#2cc9ff;--string-color:#a2db3c;--font-size:11px;--input-font-size:11px;--font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;--font-family-mono:Menlo,Monaco,Consolas,"Droid Sans Mono",monospace;--padding:4px;--spacing:4px;--widget-height:20px;--name-width:45%;--slider-knob-width:2px;--slider-input-width:27%;--color-input-width:27%;--slider-input-min-width:45px;--color-input-min-width:45px;--folder-indent:7px;--widget-padding:0 0 0 3px;--widget-border-radius:2px;--checkbox-size:calc(var(--widget-height)*0.75);--scrollbar-width:5px;background-color:var(--background-color);color:var(--text-color);font-family:var(--font-family);font-size:var(--font-size);font-style:normal;font-weight:400;line-height:1;text-align:left;touch-action:manipulation;user-select:none;-webkit-user-select:none}.lil-gui,.lil-gui *{box-sizing:border-box;margin:0;padding:0}.lil-gui.root{display:flex;flex-direction:column;width:var(--width,245px)}.lil-gui.root>.title{background:var(--title-background-color);color:var(--title-text-color)}.lil-gui.root>.children{overflow-x:hidden;overflow-y:auto}.lil-gui.root>.children::-webkit-scrollbar{background:var(--background-color);height:var(--scrollbar-width);width:var(--scrollbar-width)}.lil-gui.root>.children::-webkit-scrollbar-thumb{background:var(--focus-color);border-radius:var(--scrollbar-width)}.lil-gui.force-touch-styles{--widget-height:28px;--padding:6px;--spacing:6px;--font-size:13px;--input-font-size:16px;--folder-indent:10px;--scrollbar-width:7px;--slider-input-min-width:50px;--color-input-min-width:65px}.lil-gui.autoPlace{max-height:100%;position:fixed;right:15px;top:0;z-index:1001}.lil-gui .controller{align-items:center;display:flex;margin:var(--spacing) 0;padding:0 var(--padding)}.lil-gui .controller.disabled{opacity:.5}.lil-gui .controller.disabled,.lil-gui .controller.disabled *{pointer-events:none!important}.lil-gui .controller>.name{flex-shrink:0;line-height:var(--widget-height);min-width:var(--name-width);padding-right:var(--spacing);white-space:pre}.lil-gui .controller .widget{align-items:center;display:flex;min-height:var(--widget-height);position:relative;width:100%}.lil-gui .controller.string input{color:var(--string-color)}.lil-gui .controller.boolean .widget{cursor:pointer}.lil-gui .controller.color .display{border-radius:var(--widget-border-radius);height:var(--widget-height);position:relative;width:100%}.lil-gui .controller.color input[type=color]{cursor:pointer;height:100%;opacity:0;width:100%}.lil-gui .controller.color input[type=text]{flex-shrink:0;font-family:var(--font-family-mono);margin-left:var(--spacing);min-width:var(--color-input-min-width);width:var(--color-input-width)}.lil-gui .controller.option select{max-width:100%;opacity:0;position:absolute;width:100%}.lil-gui .controller.option .display{background:var(--widget-color);border-radius:var(--widget-border-radius);height:var(--widget-height);line-height:var(--widget-height);max-width:100%;overflow:hidden;padding-left:.55em;padding-right:1.75em;pointer-events:none;position:relative;word-break:break-all}.lil-gui .controller.option .display.active{background:var(--focus-color)}.lil-gui .controller.option .display:after{bottom:0;content:"↕";font-family:lil-gui;padding-right:.375em;position:absolute;right:0;top:0}.lil-gui .controller.option .widget,.lil-gui .controller.option select{cursor:pointer}.lil-gui .controller.number input{color:var(--number-color)}.lil-gui .controller.number.hasSlider input{flex-shrink:0;margin-left:var(--spacing);min-width:var(--slider-input-min-width);width:var(--slider-input-width)}.lil-gui .controller.number .slider{background-color:var(--widget-color);border-radius:var(--widget-border-radius);cursor:ew-resize;height:var(--widget-height);overflow:hidden;padding-right:var(--slider-knob-width);touch-action:pan-y;width:100%}.lil-gui .controller.number .slider.active{background-color:var(--focus-color)}.lil-gui .controller.number .slider.active .fill{opacity:.95}.lil-gui .controller.number .fill{border-right:var(--slider-knob-width) solid var(--number-color);box-sizing:content-box;height:100%}.lil-gui-dragging .lil-gui{--hover-color:var(--widget-color)}.lil-gui-dragging *{cursor:ew-resize!important}.lil-gui-dragging.lil-gui-vertical *{cursor:ns-resize!important}.lil-gui .title{--title-height:calc(var(--widget-height) + var(--spacing)*1.25);-webkit-tap-highlight-color:transparent;text-decoration-skip:objects;cursor:pointer;font-weight:600;height:var(--title-height);line-height:calc(var(--title-height) - 4px);outline:none;padding:0 var(--padding)}.lil-gui .title:before{content:"▾";display:inline-block;font-family:lil-gui;padding-right:2px}.lil-gui .title:active{background:var(--title-background-color);opacity:.75}.lil-gui.root>.title:focus{text-decoration:none!important}.lil-gui.closed>.title:before{content:"▸"}.lil-gui.closed>.children{opacity:0;transform:translateY(-7px)}.lil-gui.closed:not(.transition)>.children{display:none}.lil-gui.transition>.children{overflow:hidden;pointer-events:none;transition-duration:.3s;transition-property:height,opacity,transform;transition-timing-function:cubic-bezier(.2,.6,.35,1)}.lil-gui .children:empty:before{content:"Empty";display:block;font-style:italic;height:var(--widget-height);line-height:var(--widget-height);margin:var(--spacing) 0;opacity:.5;padding:0 var(--padding)}.lil-gui.root>.children>.lil-gui>.title{border-width:0;border-bottom:1px solid var(--widget-color);border-left:0 solid var(--widget-color);border-right:0 solid var(--widget-color);border-top:1px solid var(--widget-color);transition:border-color .3s}.lil-gui.root>.children>.lil-gui.closed>.title{border-bottom-color:transparent}.lil-gui+.controller{border-top:1px solid var(--widget-color);margin-top:0;padding-top:var(--spacing)}.lil-gui .lil-gui .lil-gui>.title{border:none}.lil-gui .lil-gui .lil-gui>.children{border:none;border-left:2px solid var(--widget-color);margin-left:var(--folder-indent)}.lil-gui .lil-gui .controller{border:none}.lil-gui input{-webkit-tap-highlight-color:transparent;background:var(--widget-color);border:0;border-radius:var(--widget-border-radius);color:var(--text-color);font-family:var(--font-family);font-size:var(--input-font-size);height:var(--widget-height);outline:none;width:100%}.lil-gui input:disabled{opacity:1}.lil-gui input[type=number],.lil-gui input[type=text]{padding:var(--widget-padding)}.lil-gui input[type=number]:focus,.lil-gui input[type=text]:focus{background:var(--focus-color)}.lil-gui input::-webkit-inner-spin-button,.lil-gui input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.lil-gui input[type=number]{-moz-appearance:textfield}.lil-gui input[type=checkbox]{appearance:none;-webkit-appearance:none;border-radius:var(--widget-border-radius);cursor:pointer;height:var(--checkbox-size);text-align:center;width:var(--checkbox-size)}.lil-gui input[type=checkbox]:checked:before{content:"✓";font-family:lil-gui;font-size:var(--checkbox-size);line-height:var(--checkbox-size)}.lil-gui button{-webkit-tap-highlight-color:transparent;background:var(--widget-color);border:1px solid var(--widget-color);border-radius:var(--widget-border-radius);color:var(--text-color);cursor:pointer;font-family:var(--font-family);font-size:var(--font-size);height:var(--widget-height);line-height:calc(var(--widget-height) - 4px);outline:none;text-align:center;text-transform:none;width:100%}.lil-gui button:active{background:var(--focus-color)}@font-face{font-family:lil-gui;src:url("data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUsAAsAAAAACJwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAH4AAADAImwmYE9TLzIAAAGIAAAAPwAAAGBKqH5SY21hcAAAAcgAAAD0AAACrukyyJBnbHlmAAACvAAAAF8AAACEIZpWH2hlYWQAAAMcAAAAJwAAADZfcj2zaGhlYQAAA0QAAAAYAAAAJAC5AHhobXR4AAADXAAAABAAAABMAZAAAGxvY2EAAANsAAAAFAAAACgCEgIybWF4cAAAA4AAAAAeAAAAIAEfABJuYW1lAAADoAAAASIAAAIK9SUU/XBvc3QAAATEAAAAZgAAAJCTcMc2eJxVjbEOgjAURU+hFRBK1dGRL+ALnAiToyMLEzFpnPz/eAshwSa97517c/MwwJmeB9kwPl+0cf5+uGPZXsqPu4nvZabcSZldZ6kfyWnomFY/eScKqZNWupKJO6kXN3K9uCVoL7iInPr1X5baXs3tjuMqCtzEuagm/AAlzQgPAAB4nGNgYRBlnMDAysDAYM/gBiT5oLQBAwuDJAMDEwMrMwNWEJDmmsJwgCFeXZghBcjlZMgFCzOiKOIFAB71Bb8AeJy1kjFuwkAQRZ+DwRAwBtNQRUGKQ8OdKCAWUhAgKLhIuAsVSpWz5Bbkj3dEgYiUIszqWdpZe+Z7/wB1oCYmIoboiwiLT2WjKl/jscrHfGg/pKdMkyklC5Zs2LEfHYpjcRoPzme9MWWmk3dWbK9ObkWkikOetJ554fWyoEsmdSlt+uR0pCJR34b6t/TVg1SY3sYvdf8vuiKrpyaDXDISiegp17p7579Gp3p++y7HPAiY9pmTibljrr85qSidtlg4+l25GLCaS8e6rRxNBmsnERunKbaOObRz7N72ju5vdAjYpBXHgJylOAVsMseDAPEP8LYoUHicY2BiAAEfhiAGJgZWBgZ7RnFRdnVJELCQlBSRlATJMoLV2DK4glSYs6ubq5vbKrJLSbGrgEmovDuDJVhe3VzcXFwNLCOILB/C4IuQ1xTn5FPilBTj5FPmBAB4WwoqAHicY2BkYGAA4sk1sR/j+W2+MnAzpDBgAyEMQUCSg4EJxAEAwUgFHgB4nGNgZGBgSGFggJMhDIwMqEAYAByHATJ4nGNgAIIUNEwmAABl3AGReJxjYAACIQYlBiMGJ3wQAEcQBEV4nGNgZGBgEGZgY2BiAAEQyQWEDAz/wXwGAAsPATIAAHicXdBNSsNAHAXwl35iA0UQXYnMShfS9GPZA7T7LgIu03SSpkwzYTIt1BN4Ak/gKTyAeCxfw39jZkjymzcvAwmAW/wgwHUEGDb36+jQQ3GXGot79L24jxCP4gHzF/EIr4jEIe7wxhOC3g2TMYy4Q7+Lu/SHuEd/ivt4wJd4wPxbPEKMX3GI5+DJFGaSn4qNzk8mcbKSR6xdXdhSzaOZJGtdapd4vVPbi6rP+cL7TGXOHtXKll4bY1Xl7EGnPtp7Xy2n00zyKLVHfkHBa4IcJ2oD3cgggWvt/V/FbDrUlEUJhTn/0azVWbNTNr0Ens8de1tceK9xZmfB1CPjOmPH4kitmvOubcNpmVTN3oFJyjzCvnmrwhJTzqzVj9jiSX911FjeAAB4nG3HMRKCMBBA0f0giiKi4DU8k0V2GWbIZDOh4PoWWvq6J5V8If9NVNQcaDhyouXMhY4rPTcG7jwYmXhKq8Wz+p762aNaeYXom2n3m2dLTVgsrCgFJ7OTmIkYbwIbC6vIB7WmFfAAAA==") format("woff")}@media (pointer:coarse){.lil-gui.allow-touch-styles{--widget-height:28px;--padding:6px;--spacing:6px;--font-size:13px;--input-font-size:16px;--folder-indent:10px;--scrollbar-width:7px;--slider-input-min-width:50px;--color-input-min-width:65px}}@media (hover:hover){.lil-gui .controller.color .display:hover:before{border:1px solid #fff9;border-radius:var(--widget-border-radius);bottom:0;content:" ";display:block;left:0;position:absolute;right:0;top:0}.lil-gui .controller.option .display.focus{background:var(--focus-color)}.lil-gui .controller.option .widget:hover .display{background:var(--hover-color)}.lil-gui .controller.number .slider:hover{background-color:var(--hover-color)}body:not(.lil-gui-dragging) .lil-gui .title:hover{background:var(--title-background-color);opacity:.85}.lil-gui .title:focus{text-decoration:underline var(--focus-color)}.lil-gui input:hover{background:var(--hover-color)}.lil-gui input:active{background:var(--focus-color)}.lil-gui input[type=checkbox]:focus{box-shadow:inset 0 0 0 1px var(--focus-color)}.lil-gui button:hover{background:var(--hover-color);border-color:var(--hover-color)}.lil-gui button:focus{border-color:var(--focus-color)}}'; const e = document.querySelector("head link[rel=stylesheet], head style"); e ? document.head.insertBefore(t, e) : document.head.appendChild(t) }(), Tc = !0), i ? i.appendChild(this.domElement) : e && (this.domElement.classList.add("autoPlace"), document.body.appendChild(this.domElement)), n && this.domElement.style.setProperty("--width", n + "px"), this.domElement.addEventListener("keydown", (t => t.stopPropagation())), this.domElement.addEventListener("keyup", (t => t.stopPropagation())) } add(t, e, i, n, s) { if (Object(i) === i) return new yc(this, t, e, i); switch (typeof t[e]) { case "number": return new xc(this, t, e, i, n, s); case "boolean": return new cc(this, t, e); case "string": return new bc(this, t, e); case "function": return new _c(this, t, e) } } addColor(t, e, i = 1) { return new vc(this, t, e, i) } addFolder(t) { return new Ac({ parent: this, title: t }) } load(t, e = !0) { return t.controllers && this.controllers.forEach((e => { e instanceof _c || e._name in t.controllers && e.load(t.controllers[e._name]) })), e && t.folders && this.folders.forEach((e => { e._title in t.folders && e.load(t.folders[e._title]) })), this } save(t = !0) { const e = { controllers: {}, folders: {} }; return this.controllers.forEach((t => { if (!(t instanceof _c)) { if (t._name in e.controllers) throw new Error(`Cannot save GUI with duplicate property "${t._name}"`); e.controllers[t._name] = t.save() } })), t && this.folders.forEach((t => { if (t._title in e.folders) throw new Error(`Cannot save GUI with duplicate folder "${t._title}"`); e.folders[t._title] = t.save() })), e } open(t = !0) { return this._closed = !t, this.$title.setAttribute("aria-expanded", !this._closed), this.domElement.classList.toggle("closed", this._closed), this } close() { return this.open(!1) } show(t = !0) { return this._hidden = !t, this.domElement.style.display = this._hidden ? "none" : "", this } hide() { return this.show(!1) } openAnimated(t = !0) { return this._closed = !t, this.$title.setAttribute("aria-expanded", !this._closed), requestAnimationFrame((() => { const e = this.$children.clientHeight; this.$children.style.height = e + "px", this.domElement.classList.add("transition"); const i = t => { t.target === this.$children && (this.$children.style.height = "", this.domElement.classList.remove("transition"), this.$children.removeEventListener("transitionend", i)) }; this.$children.addEventListener("transitionend", i); const n = t ? this.$children.scrollHeight : 0; this.domElement.classList.toggle("closed", !t), requestAnimationFrame((() => { this.$children.style.height = n + "px" })) })), this } title(t) { return this._title = t, this.$title.innerHTML = t, this } reset(t = !0) { return (t ? this.controllersRecursive() : this.controllers).forEach((t => t.reset())), this } onChange(t) { return this._onChange = t, this } _callOnChange(t) { this.parent && this.parent._callOnChange(t), void 0 !== this._onChange && this._onChange.call(this, { object: t.object, property: t.property, value: t.getValue(), controller: t }) } onFinishChange(t) { return this._onFinishChange = t, this } _callOnFinishChange(t) { this.parent && this.parent._callOnFinishChange(t), void 0 !== this._onFinishChange && this._onFinishChange.call(this, { object: t.object, property: t.property, value: t.getValue(), controller: t }) } destroy() { this.parent && (this.parent.children.splice(this.parent.children.indexOf(this), 1), this.parent.folders.splice(this.parent.folders.indexOf(this), 1)), this.domElement.parentElement && this.domElement.parentElement.removeChild(this.domElement), Array.from(this.children).forEach((t => t.destroy())) } controllersRecursive() { let t = Array.from(this.controllers); return this.folders.forEach((e => { t = t.concat(e.controllersRecursive()) })), t } foldersRecursive() { let t = Array.from(this.folders); return this.folders.forEach((e => { t = t.concat(e.foldersRecursive()) })), t } } function Ec(t) { switch (wc = t, Sc = t.viewerModel, w) { case "dev": Pc(), function () { Mc || (Mc = new Ac); const t = Mc.addFolder("Helper"); t.add({ "Axes Helper": !1 }, "Axes Helper").onChange((t => { t ? wc.viewerModel.modelGroup.add(new Xo(10)) : wc.viewerModel.modelGroup.remove(wc.viewerModel.modelGroup.children.find((t => "AxesHelper" == t.type))) })), t.add({ "Grid Helper": !1 }, "Grid Helper").onChange((t => { t ? wc.viewerModel.modelGroup.add(new Wo(10)) : wc.viewerModel.modelGroup.remove(wc.viewerModel.modelGroup.children.find((t => "GridHelper" == t.type))) })) }(), Lc(), ((t, e) => { const i = v("div.v3d-dev-text", document.body); v(`div${e}`, i).innerHTML = t })(navigator.userAgent, "#agent"); break; case "design": Ic(t), function () { Mc || (Mc = new Ac), wc.controls.minDistance = 0, wc.controls.maxDistance = 1 / 0; const t = { cameraSetting: Mc.addFolder("Camera Setting"), positionSetting: Mc.addFolder("Set Position") }; t.cameraSetting.add({ "camera fov": wc.camera.fov }, "camera fov", 0, 90).step(1).onChange((t => { wc.camera.fov = t, wc.camera.updateProjectionMatrix() })), t.cameraSetting.add({ "camera aspect": wc.camera.aspect }, "camera aspect", 0, 4).step(.1).onChange((t => { wc.camera.aspect = t, wc.camera.updateProjectionMatrix() })), t.cameraSetting.add({ "camera far": wc.camera.far }, "camera far", 0, 4e3).step(100).onChange((t => { wc.camera.far = t, wc.camera.updateProjectionMatrix() })), t.cameraSetting.add({ "camera filmGauge": wc.camera.filmGauge }, "camera filmGauge", 1, 1e3).step(1).onChange((t => { wc.camera.filmGauge = t, wc.camera.updateProjectionMatrix() })), t.cameraSetting.add({ "camera filmOffset": wc.camera.filmOffset }, "camera filmOffset", 1, 1e3).min(-1e3).step(.1).onChange((t => { wc.camera.filmOffset = t, wc.camera.updateProjectionMatrix() })); const e = { angleX: 0, angleY: 0, angleZ: 0, panX: 0, panY: 0, zoom: wc.camera.position.z, actionSetTime: 0 }; function i() { wc.viewerModel.setPosition({ angleX: e.angleX * (Math.PI / 180), angleY: e.angleY * (Math.PI / 180), angleZ: e.angleZ * (Math.PI / 180), panX: e.panX, panY: e.panY, zoom: e.zoom }, 0) } t.positionSetting.add(e, "angleX", -360, 360, 1).onChange(i), t.positionSetting.add(e, "angleY", -360, 360, 1).onChange(i), t.positionSetting.add(e, "angleZ", -360, 360, 1).onChange(i), t.positionSetting.add(e, "panX", -10, 10, .1).onChange(i), t.positionSetting.add(e, "panY", -10, 10, .1).onChange(i), t.positionSetting.add(e, "zoom", 10, 80).onChange(i).name("camera distance (zoom)"), t.positionSetting.add(e, "actionSetTime", 0, 100, 1).onChange((t => Cc(t / 100))), t.positionSetting.add({ Reset: function () { e.angleX = 0, e.angleY = 0, e.angleZ = 0, e.panX = 0, e.panY = 0, e.zoom = E, e.actionSetTime = 0, t.positionSetting.controllers.forEach((t => t.updateDisplay())), Cc(0), i() } }, "Reset"), t.positionSetting.add({ Screenshot: () => V3D.screenShot() }, "Screenshot") }(); break; case "mmd": wc.OPTIONS.autoRotation = !1, Pc(), Ic(t), Lc(), Dc(); break; case "mmd-material": wc.OPTIONS.autoRotation = !1, Ic(t), Dc(), function () { Mc || (Mc = new Ac); const t = V3D.devTools.originModel.materials; let e = wc.viewerModel.gltfObject, i = {}, n = {}; e.traverse((t => { t.isMesh && !i[t.material.name] && (i[t.material.name] = t.material) })); const s = Object.keys(i).sort(), r = Mc.addFolder("Material Mode"); function a(t) { if (n[t]) return; const e = i[t]; e.name, n[t] = r.addFolder(e.name), n[t].addColor(e, "color").onChange((e => o(t, "color", e))), n[t].addColor(e, "emissive").onChange((e => o(t, "emissive", e))), n[t].add(e, "emissiveIntensity", 0, 2, .01).step(.01).onChange((e => o(t, "emissiveIntensity", e))), n[t].add(e, "metalness", 0, 1, .01).step(.01).onChange((e => o(t, "metalness", e))), n[t].add(e, "roughness", 0, 1, .01).step(.01).onChange((e => o(t, "roughness", e))), n[t].add(e, "opacity", 0, 1, .01).step(.01).onChange((e => o(t, "opacity", e))), n[t].add(e, "depthWrite").onChange((e => o(t, "depthWrite", e))), n[t].add(e, "toneMapped").onChange((e => o(t, "toneMapped", e))), n[t].add(e, "transparent").onChange((e => o(t, "transparent", e))), n[t].add(e, "visible").onChange((e => o(t, "visible", e))), n[t].add({ X: () => function (t) { n[t].destroy(), delete n[t] }(t) }, "X") } function o(t, e, i) { const n = Sc.modelData.color.find((t => t.key === Sc.colorName)).custumMaterial, s = n.find((e => 1 === e.target.length && e.target[0] === t)); if (i = i && i.isColor ? l(i) : i, s) s.options[e] = i; else { const s = { target: [t], options: {} }; s.options[e] = i, n.push(s) } } function l(t) { return `rgb(${parseInt(255 * t.r)}, ${parseInt(255 * t.g)}, ${parseInt(255 * t.b)})` } r.add(i, "material list", s).onChange(a), r.add({ "get json": () => function () { const e = {}, i = new Set, n = new Map; e[wc.modelName] = JSON.parse(JSON.stringify(wc.modelData)), e[wc.modelName].color.forEach((t => { delete t.left, t.custumMaterial.forEach((t => { t.target.forEach((e => { if (s.includes(e)) { i.add(e); const s = n.get(e) || new Set; Object.keys(t.options).forEach((t => s.add(t))), n.set(e, s) } })) })) })), n.forEach(((i, n, s) => { e[wc.modelName].color.forEach((e => { const s = e.custumMaterial, r = s.find((t => t.target.length > 1 && t.target.includes(n))); let a = s.find((t => 1 === t.target.length && t.target[0] === n)); a || (a = { target: [n], options: {} }, s.push(a)), i.forEach((e => { const i = t[n][e]; a.options.hasOwnProperty(e) || (a.options[e] = r ? r.options[e] : i && i.isColor ? l(i) : i) })) })) })); const r = document.createElement("a"), a = new Blob([JSON.stringify(e, null, 2)], { type: "application/json" }), o = `${wc.modelName}_${(new Date).toISOString().slice(0, 16).split(/[-:TO]/g).join("_")}`; r.href = URL.createObjectURL(a), r.download = o, r.click() }() }, "get json"), window.addEventListener("changeColorAfter", (t => { !function () { i = {}, wc.productGroup.model.traverse((t => { t.isMesh && !i[t.material.name] && (i[t.material.name] = t.material) })); for (let t in n) n[t].destroy(), delete n[t], a(t) }() })) }() } } function Pc() { const t = wc.container, e = t.style.opacity; t.addEventListener("dragover", (e => { e.preventDefault(), t.style.opacity = .6 })), t.addEventListener("dragleave", (i => { t.style.opacity = e })), t.addEventListener("drop", (i => { i.preventDefault(), t.style.opacity = e; const n = i.dataTransfer.files[0], s = URL.createObjectURL(n); switch (null !== n.name.match(/(glb)|(hdr)$/g) ? n.name.match(/(glb)|(hdr)$/g)[0] : null) { case "glb": targetViewer.loadModelObject(void 0, s); break; case "hdr": (new RGBELoader).load(s, (t => { const e = new Qn(targetViewer.renderer); e.compileEquirectangularShader(), e.far = 50, targetViewer.scene.environment = e.fromEquirectangular(t).texture })) } })) } function Cc(t) { wc.viewerModel.modelGroup.children[0].mixer.setTrack(t) } function Lc() { Mc || (Mc = new Ac), Mc.add({ Screenshot: () => V3D.screenShot() }, "Screenshot") } function Dc() { Mc || (Mc = new Ac), Mc.add({ toneMapping: "ACESFilmic(무선ver)" }, "toneMapping", { None: "None", Linear: "Linear", Reinhard: "Reinhard", Cineon: "Cineon", ACESFilmic: "ACESFilmic", "ACESFilmic(무선ver)": "ACESFilmic(무선ver)", Custom: "Custom" }).onChange((function (t) { switch (t) { case "None": wc.renderer.toneMapping = 0, wc.renderer.toneMappingExposure = 1; break; case "Linear": wc.renderer.toneMapping = 1, wc.renderer.toneMappingExposure = 1; break; case "Reinhard": wc.renderer.toneMapping = 2, wc.renderer.toneMappingExposure = 1; break; case "Cineon": wc.renderer.toneMapping = 3, wc.renderer.toneMappingExposure = 1; break; case "ACESFilmic": wc.renderer.toneMapping = 4, wc.renderer.toneMappingExposure = 1; break; case "ACESFilmic(무선ver)": wc.renderer.toneMapping = 4, wc.renderer.toneMappingExposure = 1.2; break; case "Custom": wc.renderer.toneMapping = 5, wc.renderer.toneMappingExposure = 1 } })), Mc.add(wc.renderer, "toneMappingExposure", 0, 2).step(.01).listen().onChange((function (t) { wc.renderer.toneMappingExposure = t })) } function Ic(t) { Mc || (Mc = new Ac); const e = { viewerSetting: Mc.addFolder("Viewer Setting") }, i = wc.OPTIONS.modelName, n = t.productData.compareAll, s = document.querySelector(".v3d-controls__product-wrap"), r = document.querySelector(".v3d-controls__btns-wrap"); e.viewerSetting.add({ "UI hidden": !1 }, "UI hidden").onChange((t => { t ? (s.style.display = "none", r.style.display = "none") : (s.style.display = "block", r.style.display = "block") })), e.viewerSetting.add({ "Model Change": `${i}` }, "Model Change").options(n.reverse()).onChange((t => { location.href = location.href.replace(`model_name=${wc.viewerModel.modelName}`, `model_name=${t}`) })) } class Rc { constructor(t, e, i) { this.OPTIONS = new Fh(e, i), this.uiControls = new nl(this.OPTIONS, this), this.scene = new da, this.camera = new bn, this.renderer = new ca({ antialias: !0, alpha: !0 }), this.domElement = this.renderer.domElement, this.container = t || document.getElementById("viewer-container"), this.observer = null, this.isInViewport = !1, this.isInitialRendered = !1, this.initialRender = null, this.hideDimTimeout = null, this.viewerModel = null, this.devTool = null, this.isInit = !1, this.init() } async init() { this.container.appendChild(this.renderer.domElement), this.setViewerBGColor(this.OPTIONS.bgcolor), this.setDefaultSettings(), this.productData = new Uh(this.OPTIONS, this.localData), await this.productData.loadViewerData(), this.eventManager = new lc(this), this.viewerModel = new zh(this.OPTIONS, this.productData, { container: this.container, scene: this.scene, renderer: this.renderer, camera: this.camera, uiControls: this.uiControls, viewer: this }), this.controls = new Yh(this.OPTIONS, this.camera, this.viewerModel.modelGroup, this.container), this.controls.enableZoom = this.OPTIONS.useZoom, this.controls.enablePan = this.OPTIONS.usePan, this.onResize(), this.setObserver() } initAfter() { if (window.location.host.indexOf("samsung.com") { try { uh.setDecoderPath(t) } catch (t) { uh.setDecoderPath("./assets/libs/draco/") } uh.setDecoderConfig({ type: "js" }), ph.setDRACOLoader(uh) })(this.OPTIONS.backupPath + "libs/draco/") } setViewerBGColor(t) { const e = RegExp(/([0-9a-fA-F]{3}|[0-9a-fA-F]{6})/).test(t) ? "#" : ""; this.container.style.backgroundColor = e + t } setObserver() { const t = w ? 0 : 1e3; this.observer = new IntersectionObserver((e => { e.forEach((async e => { e.isIntersecting ? (this.isInViewport = !0, this.isInitialRendered ? this.render() : (this.uiControls.showLoader(), await this.viewerModel.loadViewerModels(), this.initialRender = setTimeout((() => { this.isInViewport && (this.isInitialRendered = !0, this.render(), this.viewerActive(), this.initialRender = null, clearTimeout(this.initialRender)) }), t))) : (this.isInViewport = !1, this.isInitialRendered ? this.stopRender() : (this.initialRender = null, clearTimeout(this.initialRender))) })) })), this.observer.observe(this.container) } update() { this.isInViewport && this.controls && !this.initialRender && (this.viewerModel.update(), this.controls.update()) } render() { this.isInViewport && this.isInitialRendered && (this.renderer.setAnimationLoop((t => { this.update(), this.renderer.render(this.scene, this.camera) })), this.isRender = !0, !this.isInit && this.viewerModel.isInit && this.scene.children.length > 0 && (w ? this.initAfter() : this.uiControls.els.loaderDimmed.addEventListener("transitionend", this.initAfter.bind(this)), this.uiControls.hideLoader(), this.uiControls.hideDimmed())) } stopRender() { this.renderer.setAnimationLoop(null), this.isRender = !1 } } return { makeViewer: function (e, n, s) { t || (n.modelOptionList = n, t = new i(e, n, s)) }, getViewer: function () { if (t) return t } } }(); return t }));
')); } } } } return { init: init, } })(); })(); (function () { window.flagship.features.benefits = (function () { const resize = window.flagship.common.resize; let els = {}; let currentDevice = resize.checkResolution(), prevDevice = null; const init = function () { els.section = document.querySelector('.features-benefits'); if (!!els.section) { setElements(); bindEvents(); } }; const setElements = function () { els.matchHeight = els.section.querySelector('.js-match-height'); els.headline = els.section.querySelectorAll('.common-card-title'); }; const bindEvents = function () { window.addEventListener('DOMContentLoaded', eventHandler.load, { once: true }); resize.add(eventHandler.resize); }; const eventList = { matchHeights: function () { els.matchHeight.style.height = ''; els.headline.forEach(title => { const maxHeight = Math.max(els.matchHeight.offsetHeight); title.style.height = maxHeight + 'px'; }); } } const eventHandler = { load: function () { if (currentDevice == null || currentDevice.indexOf('mobile') > -1 ? 5 : 7) { eventList.matchHeights(); } }, resize: function (currRes) { currentDevice = currRes; if (currentDevice !== prevDevice) { currentSlidesPerView = currentDevice.indexOf('mobile') > -1 ? 5 : 7; prevDevice = currentDevice; eventList.matchHeights(); } } }; return { init: init, } })(); })(); (function () { window.flagship.features.cameraSpecs = (function () { let els = {}; let objs = {}; const init = function () { els.scrollSection = document.querySelector('.js-scroller'); browserZoomedClass = [...document.documentElement.classList].find(cls => cls.startsWith('browser-zoomed-')); if (browserZoomedClass) { browserZoomedValue = parseInt(browserZoomedClass.replace('.browser-zoomed-', '')) } if (!!els.scrollSection) { setElements(); objList.setScene(); bindEvents(); } }; const setElements = function () { els.specRearItem1 = els.scrollSection.querySelector('.js-spec-rear-item1'); els.specRearItem2 = els.scrollSection.querySelector('.js-spec-rear-item2'); els.specFrontItem = els.scrollSection.querySelector('.js-spec-front-item'); els.specFrontImage = els.scrollSection.querySelector('.js-spec-front-image'); els.contentTrack = els.scrollSection.querySelector('.js-content-track'); }; const bindEvents = function () { window.addEventListener('scroll', eventHandler.scroll); }; const objList = { setScene: function () { objs.scene1 = SCROLLER({ trackElement: els.specRearItem1, useFixed: false }); objs.scene2 = SCROLLER({ trackElement: els.specRearItem2, useFixed: false }); objs.scene3 = SCROLLER({ trackElement: els.specFrontItem, useFixed: false }); } }; const eventList = { textMove1: function (progress) { if (progress > 1) { if (!els.specRearItem1.classList.contains('is-active')) { els.specRearItem1.classList.add('is-active'); } } else if (progress 1) { if (!els.specRearItem2.classList.contains('is-active')) { els.specRearItem2.classList.add('is-active'); } } else if (progress 1) { if (!els.specFrontItem.classList.contains('is-active')) { els.specFrontItem.classList.add('is-active'); } } else if (progress 23) { if (!els.specFrontImage.classList.contains('is-active')) { els.specFrontImage.classList.add('is-active'); } } else if (progress el.classList.contains('is-active')).getAttribute('data-colors') || 'blue-shadow'; const viewerOptions = { assetsPath: viewerAssetsPath, backupPath: viewerBackupPath, bgcolor: 'transparent', gestureGuide: null, useZoom: false, usePan: false, x: 0, y: 0, minAngleX: -180, minAngleY: -90, maxAngleX: 180, maxAngleY: 90, zoom: currDevice === 'mobile' ? 73 : 62 }; const modelOptionList = [{ modelName: viewerInitModel, autoRotation: null, color: viewerInitColor, screen: true, screenMode: 'on', statusToggle: 1, rotation: { x: 0, y: 0, z: 0 }, position: { x: 0, y: 0, z: 0 }, introPose: false, introPoseOnce: '', introPoseHold: 5, introPoseHoldLimit: 9999, },]; insertViewerHTML(els.viewerParent) .then(() => { const viewerLoaderImageHTML = `
`; els.section.querySelector('.v3d-loader__background-image').innerHTML = viewerLoaderImageHTML; // Flip Fold must be different because statusToggle has the opposite value if (!!viewerOptions.statusToggle) { eventList.setFoldInActiveClass(); } else { eventList.setFoldActiveClass(); } PDVIEWER.makeViewer(null, viewerOptions, modelOptionList); pdViewer = PDVIEWER.getViewer(); eventHandler.doubleClick(); // Viewer Loader image lazy load imageLoader.getLazyMedia(); imageLoader.setLazyMedia(); bgLoader.getLazyMedia(); bgLoader.setLazyMedia(); els.viewerSection.querySelector('.v3d-loader-icon').style.display = 'none'; }); } const insertViewerHTML = function (targetEl) { return new Promise((res) => { const target = targetEl ? targetEl : document.body; const viewrHTML = `
`; target.insertAdjacentHTML('beforeend', viewrHTML); res(); }); }; const bindEvents = function () { eventHandler.load(); eventHandler.viewerEvents(); eventHandler.click(); eventHandler.mousedown(); eventHandler.mouseup(); if (!isLow) { eventList.setScene(); } }; const eventHandler = { load: function () { window.addEventListener('DOMContentLoaded', eventList.load, { once: true }); }, viewerEvents: function () { window.addEventListener('viewerLoadEnd', eventList.viewerLoadEnd); window.addEventListener('mixerStart', eventList.mixerStart); }, click: function () { els.foldBtn && els.foldBtn.addEventListener('click', eventList.clickFold); els.resetBtn && els.resetBtn.addEventListener('click', eventList.clickReset); els.presetOpen && els.presetOpen.addEventListener('click', eventList.openPresetPopup); for (let i = 0; i el === document.activeElement); if (els.presetClose !== document.activeElement && !isAngleCtaFocus) { eventList.closePresetPopup(); } }, openPresetPopup: function () { if (!els.presetLayer.classList.contains('is-active')) { els.presetOpen.classList.add('is-open'); els.presetLayer.classList.add('is-active'); els.presetOpen.setAttribute('aria-expanded', true); els.presetClose.focus(); eventHandler.presetOpen(); } else { eventList.closePresetPopup(); } els.presetClose && els.presetClose.addEventListener('click', eventList.closePresetPopup); }, closePresetPopup: function (e) { if (els.presetLayer.classList.contains('is-active')) { els.presetOpen.classList.remove('is-open'); els.presetLayer.classList.remove('is-active'); els.presetOpen.setAttribute('aria-expanded', false); if (e && e.target.classList.contains('js-preset-close')) { els.presetOpen.focus(); } eventHandler.presetClose(); } }, setFoldClass: function () { if (!isLoadEnd) return; if (!pdViewer.getStatusToggleState()) { this.setFoldInActiveClass(); } else { this.setFoldActiveClass(); } }, setFoldInActiveClass: function () { if (els.foldBtn.classList.contains('is-fold')) els.foldBtn.classList.remove('is-fold'); els.foldBtn.classList.add('is-unfolded'); }, setFoldActiveClass: function () { if (els.foldBtn.classList.contains('is-unfolded')) els.foldBtn.classList.remove('is-unfolded'); els.foldBtn.classList.add('is-fold'); }, setAngle: function () { if (!isLoadEnd) return; let target = this, targetAngle = target.getAttribute('data-js-angle'); pdViewer.setModelDirection(targetAngle); accessibility.selected(target); }, setViewerAltText: function () { let altText = ''; if (typeof LOCAL_VARI != 'undefined' && !!LOCAL_VARI) { altText = LOCAL_VARI.viewer.altText; } pdViewer.setCanvasAltText(altText); } }; const accessibility = { fold: { ariaLabel: function () { if (!pdViewer.getStatusToggleState()) { els.foldBtn.setAttribute('aria-label', `${els.foldBtn.getAttribute('data-unfolded')}`); } else { els.foldBtn.setAttribute('aria-label', `${els.foldBtn.getAttribute('data-folded')}`); } }, tagging: function () { let dataOmni = els.foldBtn.getAttribute('an-tr'), gaLa = els.foldBtn.getAttribute('an-la'); if (!pdViewer.getStatusToggleState()) { if (dataOmni.indexOf('unfolded') === -1) { els.foldBtn.setAttribute('an-tr', dataOmni.replace('folded', 'unfolded')); els.foldBtn.setAttribute('an-la', gaLa.replace('folded', 'unfolded')); } } else { els.foldBtn.setAttribute('an-tr', dataOmni.replace('unfolded', 'folded')); els.foldBtn.setAttribute('an-la', gaLa.replace('unfolded', 'folded')); } }, }, selected: function (target) { for (let i = 0; i -1 ? 5 : 7, isLoadEnd = false; const init = function () { els.section = document.querySelector('.js-colors'); setElements(); setProperty(); bindEvents(); }; const setElements = function () { // panel els.panelWrap = els.section.querySelector('.js-panel-wrap'); els.panelItems = els.panelWrap.querySelectorAll('.js-panel-item'); // colorchip els.swiperContainer = colorchipWrap.querySelector('.js-colorchip-container'); els.colorchipButtons = colorchipWrap.querySelectorAll('.js-colorchip-button'); els.swiperArrowWrap = colorchipWrap.querySelector('.js-arrow-wrap'); els.swiperNextArrow = colorchipWrap.querySelector('.js-colorchip-next'); els.swiperPrevArrow = colorchipWrap.querySelector('.js-colorchip-prev'); els.colorchipNames = colorchipWrap.querySelectorAll('.js-colorchip-name'); // viewer els.viewerSection = els.section.querySelector('.js-colors-viewer'); els.viewerWrap = els.viewerSection.querySelector('.features-colors__viewer360-content'); }; const setProperty = function () { for (let i = 0; i el.classList.contains(activeClass)) || 0; } else { defaultColorIdx = Array.from(els.colorchipButtons).findIndex((el) => el.classList.contains(activeClass)) || 0; } eventList.setColors(defaultColorIdx); eventHandler.click(); eventHandler.keydown(); resize.add(eventList.resize); eventHandler.scroll(); eventHandler.viewerEvents(); }; const eventHandler = { click: function () { for (let i = 0; i = kvHeight) { // bg load colorchipWrap.bgImgs = colorchipWrap.querySelectorAll('.js-bg-img'); if (!!colorchipWrap.bgImgs) bgLoader.setResponsiveMedia(colorchipWrap.bgImgs); window.removeEventListener('scroll', eventList.scroll); } }, checkColorchipSwiper: function () { let colorchipSwiperLength = currentDevice.indexOf('mobile') > -1 ? 6 : 8; if (els.colorchipButtons.length >= colorchipSwiperLength) { if (els.swiperArrowWrap.style.display == 'none') { els.swiperArrowWrap.style.display = ''; } swiperEvents.set(); } else { if (els.swiperArrowWrap.style.display != 'none') { els.swiperArrowWrap.style.display = 'none'; } if (els.colorchipSwiper != null) { swiperEvents.destroy(); } } }, setColors: function (activeIndex) { eventList.setColorchip(activeIndex); eventList.setPanel(activeIndex); eventList.setColorName(activeIndex); // viewer if (PDVIEWER.getViewer()) { eventList.setViewerColor(activeIndex) } }, resize: function (currRes) { currentDevice = currRes; if (currentDevice !== prevDevice) { currentSlidesPerView = currentDevice.indexOf('mobile') > -1 ? 5 : 7; prevDevice = currentDevice; eventList.checkColorchipSwiper(); } }, clickColorchip: async function () { if (!isLoadEnd && !utils.isLowNetwork()) return; if (!utils.isLowNetwork() && PDVIEWER.getViewer()) { if (PDVIEWER.getViewer().viewer.isChanging) return; if (PDVIEWER.getViewer().viewer.viewerModel.isMixerRun) return; } const targetColor = this; eventList.setColors(targetColor.index); }, setViewerColor: async function (activeIndex) { const modelName = els.viewerSection.getAttribute('data-product-name'); const colorName = els.colorchipButtons[activeIndex].getAttribute('data-colors'); await PDVIEWER.getViewer().changeColor(modelName, colorName); }, setColorchip: function (activeIndex) { let targetcolorchipButton = els.colorchipButtons[activeIndex]; for (let i = 0; i -1) { isNotActivedColorchips = (i != swiperObj.activeIndex) && (i > swiperObj.activeIndex + 4) || (swiperObj.activeIndex > i); } else { isNotActivedColorchips = (i != swiperObj.activeIndex) && (i > swiperObj.activeIndex + 6) || (swiperObj.activeIndex > i); } if (isNotActivedColorchips) { utils.onAccessibility(swiperObj.slides[i]); setTimeout(function () { utils.onAccessibility(swiperObj.slides[i]); }, 300); } else { utils.offAccessibility(swiperObj.slides[i]); setTimeout(function () { utils.offAccessibility(swiperObj.slides[i]); }, 300); } } }, colorchipArrow: function (swiperObj) { if (swiperObj.isBeginning && !swiperObj.isEnd) { utils.onAccessibility(els.swiperPrevArrow); utils.offAccessibility(els.swiperNextArrow); } else if (!swiperObj.isBeginning && !swiperObj.isEnd) { utils.offAccessibility(els.swiperPrevArrow); utils.offAccessibility(els.swiperNextArrow); } else { utils.onAccessibility(els.swiperNextArrow); utils.offAccessibility(els.swiperPrevArrow); } }, selected: function (target) { if (typeof LOCAL_VARI != 'undefined' && !!LOCAL_VARI) { target.setAttribute('title', LOCAL_VARI.selected); } else { target.setAttribute('title', 'Selected'); } } }; return init(colorchipWrap); }; })(); (function () { window.flagship.features.compares = (function () { const init = function () { const compares = document.querySelectorAll('.js-compare'); for (let i = 0; i -1, touchDevice = ('ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch)); const compareData = { 'SM-F741': { modelName: 'galaxy-z-flip6', modelText: 'Galaxy Z Flip6', thickness: { A: '-0.4', B: '-0.4', }, flexWindow: '+0.7”', mp: '50', hrs: { A: '+8', B: '+8', } }, 'SM-F731': { modelName: 'galaxy-z-flip5', modelText: 'Galaxy Z Flip5', thickness: { A: '-0.4', B: '-0.4', }, flexWindow: '+0.7”', mp: '12', hrs: { A: '+11', B: '+11', } }, 'SM-F721': { modelName: 'galaxy-z-flip4', modelText: 'Galaxy Z Flip4', thickness: { A: '-0.4', B: '-0.4', }, flexWindow: '+2.2”', mp: '12', hrs: { A: '+12', B: '+12', } }, 'SM-F711': { modelName: 'galaxy-z-flip3', modelText: 'Galaxy Z Flip3', thickness: { A: '-0.4', B: '-0.4', }, flexWindow: '+2.2”', mp: '12', hrs: { A: '+15', B: '+15', } }, 'SM-S931': { modelName: 'galaxy-s25', modelText: 'Galaxy S25', thickness: { A: '-0.7', B: '-0.7', }, mp: '50', hrs: { A: '+2', B: '+2', } }, 'SM-S921': { modelName: 'galaxy-s24', modelText: 'Galaxy S24', thickness: { A: '-1.1', B: '-1.1', }, mp: '50', hrs: { A: '+3', B: '+2', } }, 'SM-S911': { modelName: 'galaxy-s23', modelText: 'Galaxy S23', thickness: { A: '-1.1', B: '-1.1', }, mp: '50', hrs: { A: '+9', B: '+9', } }, 'SM-S901': { modelName: 'galaxy-s22', modelText: 'Galaxy S22', thickness: { A: '-1.1', B: '-1.1', }, mp: '50', hrs: { A: '+13', B: '+12', } } } const init = function () { els.section = compareWrap; if (!!els.section) { setElements(); setProperty(); bindEvents(); eventList.setCompareVari(); eventList.getDeviceInfo().then((modelCode) => { const isSseries = (modelCode == 'SM-S931' || modelCode == 'SM-S921' || modelCode == 'SM-S911' || modelCode == 'SM-S901') && (els.section.type == 'battery'); if (!modelCode || !Object.keys(compareData).find((sku) => sku === modelCode) || isSseries) { modelCode = 'SM-F741'; } eventList.selectItem(modelCode); eventList.setDefault(modelCode); }); } }; const setElements = function () { els.dropdown = els.section.querySelector('.js-dropdown'); if (els.section.type === 'design') { els.flexWindowValue = els.section.querySelector('.js-flex-window-value'); els.thicknessValue = els.section.querySelector('.js-thickness-value'); els.thicknessUnits = els.section.querySelectorAll('.js-thickness-unit'); } else if (els.section.type === 'camera') { els.wideAngleTexts = els.section.querySelectorAll('.js-copy-wideangle'); els.compareMp = els.section.querySelector('.js-mp-value'); els.cameraUnits = els.section.querySelectorAll('.js-camera-unit'); els.modelName = els.section.querySelector('.js-model-name'); } else if (els.section.type === 'battery') { els.batteryValue = els.section.querySelector('.js-battery-value'); els.batteryUnit = els.section.querySelectorAll('.js-battery-unit'); els.modelName = els.section.querySelector('.js-model-name'); } }; const setProperty = function () { els.dropdown.selectBox = els.dropdown.querySelector('.js-select-box'); els.dropdown.button = els.dropdown.querySelector('.js-select-button'); els.dropdown.list = els.dropdown.querySelector('.js-select-list'); els.dropdown.listItem = els.dropdown.list.querySelectorAll('.js-select-item'); if (els.section.type === 'design') { for (let i = 0; i 0; }, dropdowntoggle: function (event) { let isExpanded = event.target.getAttribute('aria-expanded') === 'true'; event.target.setAttribute('aria-expanded', !isExpanded); if (!isExpanded) { event.target.classList.add('is-active'); eventHandler.onFocusInDropdown(); setTagging.close(event.target); } else { event.target.classList.remove('is-active'); setTagging.open(event.target); } }, checkDropdownClick: function (event) { const isButton = event.target.classList.contains('js-select-button'); const isOption = event.target.classList.contains('js-select-item'); if (!isButton && !isOption) { eventList.dropdownClose(); } }, dropdownClose: function () { els.dropdown.button.setAttribute('aria-expanded', 'false'); els.dropdown.button.classList.remove('is-active'); if (!(els.dropdown.button.getAttribute('aria-expanded') === 'true')) { setTagging.open(els.dropdown.button); } eventHandler.mouseup(); eventHandler.offDropdownClickCheck(); eventHandler.offFocusInDropdown(); accessibility.changeAiraHidden(); }, focusInDropdown: function (event) { const isInList = event.target.closest('.js-select-list'); const isButton = event.target.classList.contains('js-select-button'); if (!isInList && !(isButton && isMousedown)) { eventList.dropdownClose(); } }, clickOption: function (target) { const targetParent = target.closest('.js-dropdown'); targetParent.selectBoxButton = targetParent.querySelector('.js-select-button'); if (eventList.isDropdownSelect()) { const selectIndex = targetParent.selectBox.selectedIndex, optionList = targetParent.selectBox.options; Array.from(optionList).forEach(option => option.removeAttribute('selected')); optionList[selectIndex].setAttribute('selected', true) targetParent.button.textContent = optionList[selectIndex].textContent; } else { const selectItemDataValue = target.getAttribute('data-value'); Array.from(targetParent.selectBox.children).forEach((optionEl) => { const value = optionEl.getAttribute('value'); if (value !== selectItemDataValue) { optionEl.removeAttribute('selected'); } else { optionEl.setAttribute('selected', 'true'); } }); targetParent.selectBox.value = selectItemDataValue; targetParent.button.textContent = target.textContent; } }, setDefault: function (modelValue) { const { modelText } = compareData[modelValue]; els.dropdown.button.innerText = modelText; accessibility.changeAiraHidden(); }, clickCompareModel: function (optionEl) { const modelValue = optionEl.getAttribute('data-value') || ''; eventList.selectItem(modelValue); }, changeSelectBox: function (selectEl) { const selectedEl = Array.from(selectEl.childNodes).find((el) => el.selected); const modelValue = selectedEl.value; eventList.selectItem(modelValue); }, resize: function (currRes) { currDevice = currRes; if (currDevice != prevDevice) { eventList.responsive(); prevDevice = currDevice; } eventList.dropdownClose(); els.dropdown.selectBox.classList.remove("is-active"); }, responsive: function () { }, getDeviceInfo: function () { return new Promise((resolve, reject) => { if (navigator.userAgentData) { navigator.userAgentData.getHighEntropyValues(['model']).then((uaData) => { const modelCode = uaData.model ? uaData.model.slice(0, 7) : null; resolve(modelCode); }).catch((err) => reject(err)); } else { const compareModelList = Object.keys(compareData); const sku = compareModelList.find((sku) => navigator.userAgent.includes(sku)); resolve(sku); } }); }, setCompareVari: function () { let targetTexts = []; if (els.section.type === 'design') { targetTexts = Array.from(els.thicknessUnits); } else if (els.section.type === 'camera') { targetTexts = Array.from(els.cameraUnits) .concat(Array.from(els.wideAngleTexts)); } else if (els.section.type === 'battery') { targetTexts = Array.from(els.batteryUnit); } targetTexts.forEach((el) => { const { key, defaultText } = el; if (typeof COMPARE_VARI != 'undefined' && !!COMPARE_VARI) { el.innerText = COMPARE_VARI[key] || defaultText; } else { el.innerText = defaultText; } }); }, setCompareValueText: function (modelValue) { const { flexWindow, thickness, modelText, mp, hrs } = compareData[modelValue]; if (els.section.type === 'design') { els.flexWindowValue.innerText = flexWindow; const thicknessType = thickness[compareOption.type] ? thickness[compareOption.type] : thickness['B']; els.thicknessValue.innerText = thicknessType; if (els.flexWindowValue.innerText === '' || els.flexWindowValue.innerText === 'undefined') { const parentItem = els.flexWindowValue.closest('.features-design-compare__content-item'); if (parentItem) { parentItem.classList.add('is-none-compare'); } const items = els.section.querySelectorAll('.features-design-compare__content-item'); items.forEach(item => { item.classList.remove('is-compare'); if (!item.classList.contains('is-none-compare')) { item.classList.add('is-compare'); } else { item.classList.remove('is-compare'); } }) } else { const parentItem = els.flexWindowValue.closest('.features-design-compare__content-item'); if (parentItem) { parentItem.classList.remove('is-none-compare'); } const items = els.section.querySelectorAll('.features-design-compare__content-item'); items.forEach(item => { item.classList.remove('is-compare'); }) } } else if (els.section.type === 'camera') { els.compareMp.innerText = mp; els.modelName.innerText = modelText; } else if (els.section.type === 'battery') { const batteryType = hrs[compareOption.type] ? hrs[compareOption.type] : hrs['B']; els.batteryValue.innerText = batteryType; els.modelName.innerText = modelText; } }, selectItem: function (modelValue) { eventList.setCompareValueText(modelValue); accessibility.changeSelected(modelValue); eventList.changeSup(modelValue); if (oldValue && oldValue !== modelValue) { const textAreaList = els.section.querySelectorAll('.js-text-change'); textAreaList.forEach((textEl) => textEl.classList.remove('is-active')); setTimeout(() => textAreaList.forEach((textEl) => textEl.classList.add('is-active')), 0); } oldValue = modelValue; }, changeSup: function (modelCode) { const targetOption = Array.from(els.dropdown.selectBox.options).find((optionEl) => optionEl.getAttribute('value') === modelCode); const supItems = els.section.querySelectorAll('.js-sup'); supItems.forEach(item => { const supItemsValue = item.getAttribute('data-value'); if (!supItemsValue) { item.style.display = 'none'; eventList.moveToOriginalPosition(item); return; } const isMatch = supItemsValue.includes(',') ? supItemsValue.split(',').includes(modelCode) : supItemsValue === modelCode; if (isMatch) { item.style.display = 'inline-block'; eventList.moveElementToContainer(item); } else { item.style.display = 'none'; eventList.moveToOriginalPosition(item); } }) }, moveElementToContainer: function (element) { const parent = element.closest('.js-value-title'); if (!parent) return; const text = parent.querySelector('.js-value-text'); if (!text) return; if (element.parentElement === text) return; text.appendChild(element); }, moveToOriginalPosition: function (element) { const text = element.closest('.js-value-text'); if (!text) return; const parent = text.closest('.js-value-title'); if (!parent) return; parent.appendChild(element); }, clickSelect: function () { els.dropdown.selectBox.classList.toggle("is-active"); }, offFocusSelect: function () { if (els.dropdown.selectBox.classList.contains("is-active")) { els.dropdown.selectBox.classList.remove("is-active"); } } }; const accessibility = { changeSelected: function (modelCode) { const targetOption = Array.from(els.dropdown.selectBox.options).find((optionEl) => optionEl.getAttribute('value') === modelCode); const targetDropdownList = els.dropdown.list; const targetDropdownItem = targetDropdownList.querySelectorAll('.js-select-item'); const target = Array.from(targetDropdownItem).find((el) => el.getAttribute('data-value') === modelCode); targetOption.setAttribute('selected', true); for (let i = 0; i { // Console warning on aria-hidden on focus element accessibility.ariaHiddenTrue(els.dropdown.selectBox); accessibility.ariaHiddenFalse(els.dropdown.button); if (isOpened) { accessibility.ariaHiddenFalse(els.dropdown.list); } else { accessibility.ariaHiddenTrue(els.dropdown.list); } }); } }, ariaHiddenTrue: function (element) { element.setAttribute('aria-hidden', true); element.setAttribute('tabindex', '-1'); }, ariaHiddenFalse: function (element) { element.removeAttribute('aria-hidden'); element.removeAttribute('tabindex'); }, dropdownFocus: function () { els.dropdown.button.focus(); }, selected: function (target) { if (typeof LOCAL_VARI != 'undefined' && !!LOCAL_VARI) { target.setAttribute('title', LOCAL_VARI.selected); } else { target.setAttribute('title', 'Selected'); } } } const setTagging = { open: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('close', 'open')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('close', 'open')); } }, close: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('open', 'close')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('open', 'close')); } } }; return init(compareWrap); }; })(); (function () { window.flagship.features.display = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize; let currDevice = resize.checkResolution(); let els = {}; const init = function () { els.section = document.querySelector('.features-display-viewing'); if (!!els.section) { setElements(); bindEvents(); }; }; const setElements = function () { els.displayImage = els.section.querySelector('.features-display-viewing__image'); }; const bindEvents = function () { eventList.setScene(); eventHandler.scroll(); }; const eventHandler = { scroll: function () { window.addEventListener('scroll', eventList.scroll); } }; const eventList = { setScene: function () { els.section.scene = SCROLLER({ trackElement: els.section, resize: utils.detector.isTouchDevice ? false : true }); }, scroll: function () { els.section.scene.trackAnimation(function () { const progress = this.progress; if (currDevice === 'mobile') { eventList.changeOpacityMo(progress); } else { eventList.changeOpacity(progress); } }); }, changeOpacity: function (progress) { if (progress > 10 && progress 40) { els.displayImage.style.opacity = `100%`; } else if (progress 5 && progress 33) { els.displayImage.style.opacity = `100%`; } else if (progress 0) { for (let i = 0; i -1) { e.preventDefault(); let sectionId = this.getAttribute('href'), section = document.querySelector(`${sectionId}`), sectionTop = section.getBoundingClientRect().top, movePosition = (sectionTop + window.pageYOffset) - utils.getNavHeight(), clickable = section.querySelectorAll('a, button'), title = section.querySelector('h2') || section.querySelector('h3'); if (sectionId === '#storage') { movePosition = movePosition - ((window.innerHeight - utils.getNavHeight() - section.offsetHeight) / 2) } if (!!title) { let _focusOut = function () { title.removeAttribute('tabindex'); title.removeEventListener('focusout', _focusOut); }; title.addEventListener('focusout', _focusOut); title.setAttribute('tabindex', 0); title.focus(); } else { clickable[0].focus(); } window.scrollTo(0, movePosition); } } }; return { init: init } })(); })(); (function () { window.flagship = window.flagship || {}; window.flagship.features = window.flagship.features || {}; window.flagship.features.highlightsZone = (function () { const utils = flagship.common.utils, resize = flagship.common.resize, Swiper = flagship.Swiper; let els = { scrollVideoWraps: [] }, obj = { scrollVideo: [], scene: [], }; let swiperObj = {}; let brokenFixedStatus = null; const isRtl = document.documentElement.classList.contains('rtl'); const lowNetwork = document.documentElement.classList.contains('low_network'); let prevDevice = resize.checkResolution(); let currDevice = resize.checkResolution(); let cardButtons = []; // let time; const init = function () { els.section = document.querySelector(".features-highlights"); if (!!els.section) { setElements(); setProperty(); bindEvents(); } }; const setElements = function () { els.trackEl = els.section.querySelector('.js-scroll-track'); els.fixedEl = els.section.querySelector('.js-scroll-fixed'); els.titleEl = els.section.querySelector('.js-slide-text'); els.cardWrap = els.section.querySelector('.js-slide-wrap'); els.cardEl = els.section.querySelectorAll('.js-slide-card'); els.cardContent = els.section.querySelectorAll('.js-slide-content'); els.pagiNationEl = els.section.querySelector('.js-slide-pagination'); els.featureTagging = els.cardWrap.getAttribute('data-tagging-feature'); els.scrollVideoWraps = els.section.querySelectorAll('.js-scroll-video-mobile'); }; const setProperty = function () { let totalCards = els.cardEl.length; for (let i = 0; i { if (sceneObj && typeof sceneObj.destroy === "function") { sceneObj.destroy(); } }) obj.scene = []; } const eventHandler = { scroll: function () { window.addEventListener('scroll', eventList.setMotion); }, }; const eventList = { load: function () { const desktopStatus = currDevice === 'desktop' || currDevice === 'tablet'; eventList.updateBrokenStatus(); if (desktopStatus) { if (brokenFixedStatus) { swiperEvents.set(); } else { accessibility.setInitialActiveCard(); eventList.setScene(); eventList.setCopyScene(); eventHandler.scroll(); eventList.setMotion(); scrollerMotion.bindFocusEvent(); } clearResources(); } else { eventList.setVideo(); eventList.obsSetScene(); window.addEventListener("scroll", eventList.scroll); eventList.resizeVideo(); } }, resize: function () { currDevice = resize.checkResolution(); const desktopStatus = currDevice === 'desktop' || currDevice === 'tablet'; eventList.updateBrokenStatus(); if (desktopStatus) { if (brokenFixedStatus) { scrollerMotion.destroy(); swiperEvents.set(); } else { swiperEvents.destroy(); eventList.setScene(); eventList.setCopyScene(); eventHandler.scroll(); eventList.setMotion(); scrollerMotion.bindFocusEvent(); } } if (currDevice != prevDevice) { if (desktopStatus) { if (brokenFixedStatus) { scrollerMotion.destroy(); swiperEvents.set(); } else { accessibility.setInitialActiveCard(); swiperEvents.destroy(); eventList.setScene(); eventList.setCopyScene(); eventHandler.scroll(); eventList.setMotion(); scrollerMotion.bindFocusEvent(); } clearResources(); } else { swiperEvents.destroy(); scrollerMotion.destroy(); eventList.setVideo(); eventList.obsSetScene(); window.addEventListener("scroll", eventList.scroll); eventList.resizeVideo(); } prevDevice = currDevice; } }, updateBrokenStatus: function () { const usedFixedClass = els.section.classList.contains('is-used-fixed'); const isMobile = currDevice.indexOf('mobile') > -1 const contentHeightVw = 47.91667; const contentHeightPx = 700; let contentHeight = window.innerWidth >= 1440 ? contentHeightPx : window.innerWidth / 100 * contentHeightVw; let navHeight = isMobile ? window.innerWidth * 0.2666666667 : 96; const innerHeight = window.innerHeight - navHeight; checkbrokenFixed = contentHeight >= innerHeight && !isMobile; if (checkbrokenFixed || !usedFixedClass || lowNetwork) { els.section.classList.add('is-broken-fixed'); brokenFixedStatus = true; } else { els.section.classList.remove('is-broken-fixed'); brokenFixedStatus = false; } }, setScene: function () { const { trackHeight } = scrollerMotion.scrollSettings(); if (!els.trackEl.scene || els.trackEl.scene == null) { els.trackEl.scene = SCROLLER({ trackElement: els.trackEl, fixedElement: els.fixedEl, useFixed: true, useFixedStyle: false, trackHeight: trackHeight, correction: 0.5, resize: utils.detector.isTouchDevice ? false : true }); scrollerMotion.createPagination(); } }, setCopyScene: function () { if (!els.cardWrap.scene || els.cardWrap.scene == null) { els.cardWrap.scene = SCROLLER({ trackElement: els.cardWrap, resize: utils.detector.isTouchDevice ? false : true }); } }, setVideo: function () { for (let i = 0; i -1) ? els.scrollVideoWraps[i].moStartPoint : els.scrollVideoWraps[i].startPoint, reversePoint: (currDevice.indexOf('mobile') > -1) ? els.scrollVideoWraps[i].moReversePoint : els.scrollVideoWraps[i].reversePoint, wrap: els.scrollVideoWraps[i], video: els.scrollVideoWraps[i].video, controller: els.scrollVideoWraps[i].controller, resetCallback: function () { }, playCallback: function () { setTagging.pause(this.controller); }, pauseCallback: function () { setTagging.play(this.controller); }, endCallback: function () { } }); } }, obsSetScene: function () { for (let i = 0; i = 4) { video.play(); } else { video.addEventListener('canplay', eventList.playVideoOnce, { once: true }); } } }, pauseVideo: function (video) { for (let i = 0; i = 535 && window.innerWidth = inStart && progress = inEnd; let isIndexChange = (checkActiveCard || checkFirstCard || checkLastCard); if (isIndexChange) { currentIndex = i; break; } }; scrollerMotion.updatePaginationStatus(currentIndex); accessibility.card(currentIndex); }, updateVideoStatus: function (progress, cardSettings) { for (let i = 0; i = videoStart && progress `; }; paginNtion.innerHTML = html; }, updatePaginationStatus: function (currentIndex) { let pagiNationList = els.pagiNationEl.querySelectorAll('li'); pagiNationList.forEach(function (item, idx) { const itemButton = item.querySelector('button'); const cardTitle = els.cardEl[idx].getAttribute('data-card-title') || ''; if (idx === currentIndex) { item.classList.add('is-active'); itemButton.setAttribute('aria-label', `${LOCAL_VARI.slide}${idx + 1} ${LOCAL_VARI.selected}: ${cardTitle}`); } else { item.classList.remove('is-active'); itemButton.setAttribute('aria-label', `${LOCAL_VARI.slide}${idx + 1}: ${cardTitle}`); } }); }, showPagination: function (progress) { if (progress = 6) { els.pagiNationEl.parentElement.classList.add('is-show'); } }, clickPagination: function (cardSettings) { const buttons = els.section.querySelectorAll('.features-highlights__pagination-button'); buttons.forEach(function (btn, index) { const track = els.trackEl; let startOffset = (track.getBoundingClientRect().top + window.scrollY) - (window.innerHeight / 2); let realPercentValue = (Math.round((track.clientHeight - window.innerHeight) / 100)); btn.addEventListener('click', function () { let moveSize = startOffset + realPercentValue * cardSettings[index].cardInEnd * cardSettings[index].paginationCorrection; window.scrollTo({ top: moveSize, behavior: 'smooth' }); }); }); }, bindFocusEvent: function () { const desktopStatus = currDevice === 'desktop' || currDevice === 'tablet'; if (!brokenFixedStatus && desktopStatus && cardButtons.length === 0) { const { totalCards, cardSettings } = scrollerMotion.scrollSettings(); const track = els.trackEl; let startOffset = (track.getBoundingClientRect().top + window.scrollY) - (window.innerHeight / 2); let realPercentValue = (Math.round((track.clientHeight - window.innerHeight) / 100)); cardButtons = []; cardButtons.length = 0; for (let i = 0; i { if ((currDevice.indexOf('mobile') > -1)) return; window.scrollTo({ top: offset, behavior: 'smooth' }); btn.focus(); }, 100); } })(focusButton, moveSize); focusButton.addEventListener('focusin', onFocusIn); cardButtons.push({ el: focusButton, inHandler: onFocusIn }); } } }, unbindFocusEvent: function () { cardButtons.forEach(function (item) { item.el.removeEventListener('focusin', item.inHandler); }); cardButtons = []; cardButtons.length = 0; }, destroy: function () { if (els.trackEl.scene && els.cardWrap.scene) { els.trackEl.scene.destroy(); els.cardWrap.scene.destroy(); els.trackEl.scene = null; els.cardWrap.scene = null; els.pagiNationEl.parentElement.classList.remove('is-show'); setTimeout(() => { els.titleEl.removeAttribute('style'); els.cardContent.forEach(function (card) { card.removeAttribute('style'); }); }, 100); window.removeEventListener('scroll', eventList.setMotion); scrollerMotion.unbindFocusEvent(); accessibility.cardReset(); } } }; const swiperEvents = { set: function () { if (swiperObj.main == null) { swiperObj.main = new Swiper(els.cardWrap, { effect: 'creative', direction: 'vertical', speed: 600, slidesPerView: 1, a11y: false, creativeEffect: { prev: { translate: [0, "-100%", 0, -1], }, next: { translate: [0, "100%", 0, 0], }, }, pagination: { el: els.pagiNationEl, clickable: true, renderBullet: function (index, className) { const slide = this.slides[index]; const cardTagging = slide.getAttribute('data-card-name') || ''; const slideTitle = slide.getAttribute('data-card-title') || ''; const tagging = { omniType: "microsite_contentinter", actionType: "gallery", contentType: "feature gallery", taggingValue: els.featureTagging + ":index:" + `${cardTagging}` } this.slideTitle = slideTitle; return ` `; } }, on: { init: function () { accessibility.card(this.activeIndex); }, slideChange: function () { accessibility.card(this.activeIndex); }, } }); } }, destroy: function () { if (swiperObj.main) { swiperObj.main.destroy(true); swiperObj.main = null; accessibility.cardReset(); } }, }; const setTagging = { play: function (targetController) { if (targetController.hasAttribute('an-tr')) { let dataOmni = targetController.getAttribute('an-tr').toLowerCase(); targetController.setAttribute('an-tr', dataOmni.replace('pause', 'play')); } if (targetController.hasAttribute('an-la')) { let gaLa = targetController.getAttribute('an-la').toLowerCase(); targetController.setAttribute('an-la', gaLa.replace('pause', 'play')); } }, pause: function (targetController) { if (targetController.hasAttribute('an-tr')) { let dataOmni = targetController.getAttribute('an-tr').toLowerCase(); targetController.setAttribute('an-tr', dataOmni.replace('play', 'pause')); } if (targetController.hasAttribute('an-la')) { let gaLa = targetController.getAttribute('an-la').toLowerCase(); targetController.setAttribute('an-la', gaLa.replace('play', 'pause')); } } }; const accessibility = { card: function (currentIndex) { els.cardEl.forEach(function (carditem, index) { if (index === currentIndex) { utils.offAccessibility(carditem); } else { utils.onAccessibility(carditem); } }); }, cardReset: function () { els.cardEl.forEach(function (carditem) { utils.offAccessibility(carditem); }); }, setInitialActiveCard: function () { const { cards, totalCards, } = scrollerMotion.scrollSettings(); if (!cards || !totalCards) return; els.cardEl.forEach(function (carditem, index) { if (index === 0) { carditem.classList.add('is-active'); utils.offAccessibility(carditem); } else { carditem.classList.remove('is-active'); utils.onAccessibility(carditem); } }); } }; return { init: init, }; })(); })(); ; (function () { window.flagship.features.kv = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize; let els = {}, obj = {}, currDevice = resize.checkResolution(), prevDevice = null, isTabletRatio = null; const init = function () { els.section = document.querySelector('.js-kv'); els.hasOffer = document.querySelector('.features-kv__anchor'); if (!!els.section) { setElements(); bindEvents(); } if (!!els.hasOffer) { setElementsOffer(); bindEventsOffer(); } }; const setElementsOffer = function () { els.kvDropdown = els.section.querySelector('.js-kv-dropdown'); els.kvDropdownItem = els.section.querySelector('.features-kv__description'); els.kvDropdownSpan = els.section.querySelector('.js-button-text'); els.kvDropdownDataOmni = els.kvDropdown.getAttribute('an-tr'); els.kvDropdownGaLa = els.kvDropdown.getAttribute('an-la'); els.kvDropdownItemArrow = els.section.querySelector('.js-kv-dropdown svg'); }; const setElements = function () { els.kvInner = els.section.querySelector('.js-kv-inner'); }; const bindEventsOffer = function () { eventHandler.click(); eventList.defaultText(); eventList.getSpanHeight(); }; const bindEvents = function () { objList.setScene(); resize.add(eventList.resize); eventHandler.scroll(); }; const objList = { setScene: function () { obj.scene = SCROLLER({ trackElement: els.kvInner, useFixed: false, resize: utils.detector.isTouchDevice ? false : true }) } } const eventHandler = { click: function () { els.kvDropdown.addEventListener('click', eventList.click); }, scroll: function () { window.addEventListener('scroll', eventList.setTrack); } } const eventList = { defaultText: function () { const openText = els.kvDropdownSpan.getAttribute('data-open-text'); els.kvDropdownSpan.textContent = openText; }, click: function () { const openText = els.kvDropdownSpan.getAttribute('data-open-text'); const closeText = els.kvDropdownSpan.getAttribute('data-close-text'); if (els.kvDropdownItem.classList.contains('is-open')) { els.kvDropdownItem.classList.remove('is-open'); els.kvDropdown.classList.remove('is-active'); els.kvDropdown.setAttribute('an-la', els.kvDropdownDataOmni.replace('close', 'open')); els.kvDropdown.setAttribute('an-tr', els.kvDropdownGaLa.replace('close', 'open')); els.kvDropdownSpan.textContent = openText; } else { els.kvDropdownItem.classList.add('is-open'); els.kvDropdown.classList.add('is-active'); els.kvDropdown.setAttribute('an-la', els.kvDropdownDataOmni.replace('open', 'close')); els.kvDropdown.setAttribute('an-tr', els.kvDropdownGaLa.replace('open', 'close')); els.kvDropdownSpan.textContent = closeText; } }, getSpanHeight: function () { els.kvDropdownItem.classList.remove('features-kv__description'); els.kvDropdownItem.classList.add('full-text'); const originalHeight = els.kvDropdownItem.offsetHeight; els.kvDropdownItem.classList.add('features-kv__description'); els.kvDropdownItem.classList.remove('full-text'); if (originalHeight = 1.33 && aspectRatio = 1.33 && aspectRatio = activeIndex && i = 4) { els.deviceVideo.play(); } else { els.deviceVideo.addEventListener('canplay', function () { this.play(); }, { once: true }); } }, deviceVideoPause: function (target) { if (target.currentTime == 0) { els.deviceVideo.pause(); els.deviceVideo.currentTime = 0; } else if (target.currentTime != target.duration) { els.deviceVideo.pause(); } }, setScene: function () { objs.scene = SCROLLER({ trackElement: els.section, useFixed: false, useStrictMode: false, resize: utils.detector.isTouchDevice ? false : true }); }, activeHeadline: function (progress) { if (progress > 5) { if (!els.headline.classList.contains('is-active')) { els.headline.classList.add('is-active'); } } else if (progress 50) { if (!els.device.classList.contains('is-active')) { els.device.classList.add('is-active'); } } else if (progress == 0) { els.device.classList.remove('is-active'); } }, scrollContents: function (progress) { if (!!!(resize.checkResolution().indexOf('mobile') > -1)) { if (progress 85) { if (!!!els.fullVideo.classList.contains('is-paused')) { setTimeout(() => { els.fullVideo.currentTime = 0 ? els.deviceVideo.currentTime = 0 : els.deviceVideo.currentTime = els.fullVideo.currentTime; }, 100); } } let contentsTransformValue = utils.calRange({ targetValue: 20, progress: progress, startPoint: 10, endPoint: 20 }) const targetY = 20 - (contentsTransformValue); TweenMax.to(els.contents, 0.35, { yPercent: targetY }); } else { let contentsTransformValue = utils.calRange({ targetValue: 20, progress: progress, startPoint: 15, endPoint: 30 }) const targetY = 20 - (contentsTransformValue); TweenMax.to(els.contents, 0.35, { yPercent: targetY }); } } }; const eventHandler = { scroll: function () { objs.scene.trackAnimation(function () { let progress = this.progress; eventList.activeHeadline(progress); eventList.activeImage(progress); eventList.scrollContents(progress) }); }, play: function () { els.fullVideo.addEventListener('play', function () { eventList.deviceVideoPlay(); }) }, pause: function () { els.fullVideo.addEventListener('pause', function (e) { eventList.deviceVideoPause(e.target); }) } }; return { init: init, } })(); })(); (function () { window.flagship.features.privacy = (function () { const utils = window.flagship.common.utils, resize = flagship.common.resize; let els = {}, prevDevice = resize.checkResolution(), currDevice = resize.checkResolution(); const init = function () { els.section = document.querySelector('.features-privacy'); if (!!els.section) { setElements(); bindEvents(); } }; const setElements = function () { els.deviceImageBlur = els.section.querySelector('.js-device-blur'); els.deviceImage = els.section.querySelector('.js-device-img'); els.guardImage = els.section.querySelector('.js-guard-img'); els.privacyList = els.section.querySelector('.js-privacy-list'); els.switchTexts = els.section.querySelectorAll('.js-privacy-change'); els.safari = document.querySelector('.safari') !== null; }; const bindEvents = function () { resize.add(eventList.resize); eventList.setScene(); eventList.initText(); eventHandler.load(); eventHandler.scroll(); }; const eventHandler = { load: function () { window.addEventListener('load', function () { if (currDevice.indexOf('mobile') > -1) { eventList.setAccordion(); } }) }, scroll: function () { window.addEventListener('scroll', function () { eventList.moveMotion(); }); } }; const eventList = { resize: function (currRes) { currDevice = currRes; if (currDevice != prevDevice) { eventList.changeText(); eventList.checkAccordionInit(); prevDevice = currDevice; } }, checkAccordionInit: function () { if (currDevice.indexOf('mobile') > -1) { if (!els.accordion) { const items = els.privacyList.querySelectorAll('.js-privacy-item'); items[0].classList.add('is-open'); eventList.setAccordion(); } } else { if (els.accordion) { eventList.destroyAccordion(); } } }, setAccordion: function () { els.accordion = new window.flagship.common.accordion({ wrap: els.privacyList, classList: { item: 'js-privacy-item', button: 'js-privacy-open', contents: 'js-privacy-answer', activeClass: 'is-open' }, openType: 'single', open: { start: function (target) { let targetInnerCta = target.querySelector('.js-featue-cta'); if (targetInnerCta) targetInnerCta.addEventListener('click', accessibility.moveFocus); setTagging.close(target) } }, close: { start: function (target) { setTagging.open(target) } } }); els.accordion.init(); }, changeText: function () { els.switchTexts.forEach(text => { const headTitle = text.querySelector('.common-text'); const buttonTitle = text.nextElementSibling.querySelector('.common-text'); if (currDevice.indexOf('mobile') > -1) { buttonTitle.innerText = text.titleText; headTitle.innerText = text.emptyText; } else { headTitle.innerText = text.titleText; buttonTitle.innerText = text.emptyText; } }); }, initText: function () { els.switchTexts.forEach(text => { text.titleText = text.querySelector('.common-text').innerText; text.emptyText = ''; const headTitle = text.querySelector('.common-text'); const buttonTitle = text.nextElementSibling.querySelector('.common-text'); if (currDevice.indexOf('mobile') > -1) { headTitle.innerText = text.emptyText; buttonTitle.innerText = text.titleText; } }); }, destroyAccordion: function () { if (els.accordion) { els.accordion.destroy(); els.accordion = null; } }, setScene: function () { els.scene = SCROLLER({ trackElement: els.section, useFixed: false, resize: utils.detector.isTouchDevice ? false : true }); }, moveMotion: function () { els.scene.trackAnimation(function () { let progress = this.progress; let pointProgress = resize.checkResolution().indexOf('mobile') > -1 ? 28 : 35; if (progress == 0) { els.guardImage.classList.remove('is-active'); if (els.safari) { els.deviceImageBlur.classList.remove('is-active'); } else { els.deviceImage.classList.remove('is-active'); } }; if (progress >= pointProgress) { els.guardImage.classList.add('is-active'); if (els.safari) { els.deviceImageBlur.classList.add('is-active'); } else { els.deviceImage.classList.add('is-active'); } }; }); } }; const setTagging = { open: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('close', 'open')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('close', 'open')); } }, close: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('open', 'close')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('open', 'close')); } } }; return { init: init } })(); })(); (function () { window.flagship = window.flagship || {}; window.flagship.features = window.flagship.features || {}; window.flagship.features.reviews = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize; const bvSelector = { rating: { starsWrap: '.bv_stars_component_container', avgRatingWrap: '.bv_avgRating_component_container', numReviewWrap: '.bv_numReviews_component_container', numReviewText: '.bv_numReviews_text', }, out: { ratingContent: '.bv_rating_content2', reviewText: '.krTpQg', starsWrap: '.iyfZNQ', } } let els = {}, prevDevice = null, currDevice = resize.checkResolution(), isBvRatingSummaryLoaded = false, isBvOutSummaryLoaded = false, addedBvData = { ratingSummary: { isAdded: false, starsEl: null, avg: null, numReviews: '(0)' }, outSummary: { isAdded: false, starsEl: null, avg: null, numReviews: '(0)' } }; const init = function () { els.section = document.querySelector('.features-reviews'); if (els.section !== null) { setElements(); bindEvents(); } }; const setElements = function () { els.siteCode = document.getElementById('siteCode'); els.reviewUseYN = document.getElementById('reviewUseYN'); els.floatingNavHeadline = document.querySelector('.floating-navigation__headline-text'); els.kvSection = document.querySelector('.features-kv'); els.seeReviewsAnchor = els.kvSection.querySelector('.js-see-reviews'); els.kvReviewRating = els.kvSection.querySelector('.features-kv__reviews'); els.kvReviewAnchor = els.kvReviewRating.querySelector('.js-review-cta'); els.kvReviewAvg = els.kvReviewRating.querySelector('.features-kv__reviews-avg'); els.kvReviewNumText = els.kvReviewRating.querySelector('.features-kv__reviews-text'); els.innerWrap = els.section.querySelector('.common-inner'); els.reviewsArea = els.section.querySelector('.js-reviews-area'); els.reviewsOpener = els.section.querySelector('.js-reviews-open'); els.reviewsContent = els.section.querySelector('.js-reviews-content'); els.reviewsInner = els.section.querySelector('.features-reviews__content-inner'); } const bindEvents = function () { try { eventHandler.loadBv(); } catch (err) { eventList.hideReviews(); } resize.add(eventList.resize); }; const eventHandler = { loadBv: function () { const bvLocalData = { "ae": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_ae/main_site/production/en_AE/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_ae/main_site/production/en_AE/bv.js" ] }, "ae_ar": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-ar_ae/main_site/production/ar_AE/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-ar_ae/main_site/production/ar_AE/bv.js" ] }, "al": { "sku": "SM-F766BZKGEUC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-sq_al/main_site/production/sq_AL/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-sq_al/main_site/production/sq_AL/bv.js" ] }, "ar": { "sku": "SM-F766BDBKARO", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-es_ar/main_site/production/es_AR/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-es_pe/main_site/production/es_PE/bv.js" ] }, "at": { "sku": "SM-F766BDBGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-de_at/main_site/production/de_AT/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-DE_AT/main_site/production/de_AT/bv.js" ] }, "au": { "sku": "SM-F766BDBEATS", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_au/main_site/production/en_AU/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_au/main_site/production/en_AU/bv.js" ] }, "ba": { "sku": "SM-F766BDBGEUC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-bs_ba/main_site/production/bs_BA/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-bs_ba/main_site/production/bs_BA/bv.js" ] }, "be": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-nl_be/main_site/production/nl_BE/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-NL_BE/main_site/production/nl_BE/bv.js" ] }, "be_fr": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-fr_be/main_site/production/fr_BE/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-FR_BE/main_site/production/fr_BE/bv.js" ] }, "bg": { "sku": "SM-F766BDBGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-bg_bg/main_site/production/bg_BG/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-bg_bg/main_site/production/bg_BG/bv.js" ] }, "br": { "sku": "SM-F766BDBXZTO", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-pt_br/main_site/production/pt_BR/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-PT_BR/main_site/production/pt_BR/bv.js" ] }, "ca": { "sku": "SM-F766WDBEXAC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_ca/main_site/production/en_CA/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-EN_CA/main_site/production/en_CA/bv.js" ] }, "ca_fr": { "sku": "SM-F766WDBEXAC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-fr_ca/main_site/production/fr_CA/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-FR_CA/main_site/production/fr_CA/bv.js" ] }, "ch": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-de_ch/main_site/production/de_CH/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-de_ch/main_site/production/de_CH/bv.js" ] }, "ch_fr": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-fr_ch/main_site/production/fr_CH/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-FR_CH/main_site/production/fr_CH/bv.js" ] }, "cz": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-cs_cz/main_site/production/cs_CZ/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-CZ/main_site/production/cz/bv.js" ] }, "de": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-de_de/main_site/production/de_DE/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-DE_DE/main_site/production/de_DE/bv.js" ] }, "dk": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-da_dk/main_site/production/da_DK/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-DA_DK/main_site/production/da_DK/bv.js" ] }, "ee": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-et_ee/main_site/production/et_EE/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-et_ee/main_site/production/et_EE/bv.js " ] }, "es": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-es_es/main_site/production/es_ES/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-ES_ES/main_site/production/es_ES/bv.js" ] }, "fi": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-fi_fi/main_site/production/fi_FI/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-FI_FI/main_site/production/fi_FI/bv.js" ] }, "fr": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-fr_fr/main_site/production/fr_FR/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-FR_FR/main_site/production/fr_FR/bv.js" ] }, "hk": { "sku": "SM-F7660ZKETGY", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-zh_hk/main_site/production/zh_HK/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-zh_hk/main_site/production/zh_HK/bv.js" ] }, "hk_en": { "sku": "SM-F7660ZKETGY", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_hk/main_site/production/en_HK/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_hk/main_site/production/en_HK/bv.js" ] }, "hr": { "sku": "SM-F766BDBGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-hr_hr/main_site/production/hr_HR/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-hr_hr/main_site/production/hr_HR/bv.js" ] }, "hu": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-hu_hu/main_site/production/hu_HU/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-hu_hu/main_site/production/hu_HU/bv.js" ] }, "id": { "sku": "SM-F766BDBEXID", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-id_id/main_site/production/id_ID/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-id_id/main_site/production/id_ID/bv.js" ] }, "il": { "sku": "SM-F766BDBEMEC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-he_il/main_site/production/he_IL/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-he_il/main_site/production/he_IL/bv.js" ] }, "in": { "sku": "SM-F766BDBEINS", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_in/main_site/production/en_IN/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-EN_IN/main_site/production/en_IN/bv.js" ] }, "it": { "sku": "SM-F766BDBGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-it_it/main_site/production/it_IT/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-IT_IT/main_site/production/it_IT/bv.js" ] }, "jp": { "sku": "SM-F766QDBASJP", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-ja_jp/main_site/production/ja_JP/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-ja_jp/main_site/production/ja_JP/bv.js" ] }, "latin": { "sku": "SM-F766BDBKGTO", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-es_pa/main_site/production/es_PA/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-es_pa/main_site/production/es_PA/bv.js" ] }, "levant": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_lb/main_site/production/en_LB/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_lb/main_site/production/en_LB/bv.js" ] }, "levant_ar": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-ar_lb/main_site/production/ar_LB/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-ar_lb/main_site/production/ar_LB/bv.js" ] }, "lt": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-lt_lt/main_site/production/lt_LT/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-LT_LT/main_site/production/lt_LT/bv.js" ] }, "lv": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-lv_lv/main_site/production/lv_LV/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-lv_lv/main_site/production/lv_LV/bv.js" ] }, "mk": { "sku": "SM-F766BDBGEUC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-mk_mk/main_site/production/mk_MK/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-mk_mk/main_site/production/mk_MK/bv.js" ] }, "mx": { "sku": "SM-F766BDBKLTM", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-es_mx/main_site/production/es_MX/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-es_mx/main_site/production/es_MX/bv.js" ] }, "my": { "sku": "SM-F766BDBEXME", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_my/main_site/production/en_MY/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_my/main_site/production/en_MY/bv.js" ] }, "nl": { "sku": "SM-F766BDBHEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-nl_nl/main_site/production/nl_NL/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-NL_NL/main_site/production/nl_NL/bv.js" ] }, "no": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-no_no/main_site/production/no_NO/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-NO_NO/main_site/production/no_NO/bv.js" ] }, "nz": { "sku": "SM-F766BDBEXNZ", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_nz/main_site/production/en_NZ/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-EN_NZ/main_site/production/en_NZ/bv.js" ] }, "ph": { "sku": "SM-F766BDBEPHL", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_ph/main_site/production/en_PH/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_ph/main_site/production/en_PH/bv.js" ] }, "pl": { "sku": "SM-F766BZKGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-pl_pl/main_site/production/pl_PL/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-PL_PL/main_site/production/pl_PL/bv.js" ] }, "pt": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-pt_pt/main_site/production/pt_PT/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-PT_PT/main_site/production/pt_PT/bv.js" ] }, "ro": { "sku": "SM-F766BZRGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-ro_ro/main_site/production/ro_RO/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-ro_ro/main_site/production/ro_RO/bv.js" ] }, "rs": { "sku": "SM-F766BZKGEUC", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-sr_rs/main_site/production/sr_RS/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-sr_rs/main_site/production/sr_RS/bv.js" ] }, "sa": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-ar_sa/main_site/production/ar_SA/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-ar_sa/main_site/production/ar_SA/bv.js" ] }, "sa_en": { "sku": "SM-F766BDBEMEA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_sa/main_site/production/en_SA/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_sa/main_site/production/en_SA/bv.js" ] }, "se": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-sv_se/main_site/production/sv_SE/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-SV_SE/main_site/production/sv_SE/bv.js" ] }, "sg": { "sku": "SM-F766BDBEXSP", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_sg/main_site/production/en_SG/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-en_sg/main_site/production/en_SG/bv.js" ] }, "si": { "sku": "SM-F766BDBGEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-sl_si/main_site/production/sl_SI/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-sl_si/main_site/production/sl_SI/bv.js" ] }, "sk": { "sku": "SM-F766BDBHEUE", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-sk_sk/main_site/production/sk_SK/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-SK/main_site/production/sk/bv.js" ] }, "th": { "sku": "SM-F766BDBETHL", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-th_th/main_site/production/th_TH/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-th_th/main_site/production/th_TH/bv.js" ] }, "tr": { "sku": "SM-F766BDBHTUR", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-tr_tr/main_site/production/tr_TR/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-TR_TR/main_site/production/tr_TR/bv.js" ] }, "tw": { "sku": "SM-F7660DBABRI", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-zh_tw/main_site/production/zh_TW/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-zh_tw/main_site/production/zh_TW/bv.js" ] }, "ua": { "sku": "SM-F766BDBHSEK", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-uk_ua/main_site/production/uk_UA/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-uk_ua/main_site/production/uk_UA/bv.js" ] }, "uk": { "sku": "SM-F766BDBGEUB", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_gb/main_site/production/en_GB/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-UK_UK/main_site/production/uk_UK/bv.js" ] }, "us": { "sku": "SM-F766UDBEXAA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung/main_site/production/en_US/bv.js" ] }, "vn": { "sku": "SM-F766BDBEXXV", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-vi_vn/main_site/production/vi_VN/bv.js", "https://apps.bazaarvoice.com/deployments/samsung-vi_vn/main_site/production/vi_VN/bv.js" ] }, "za": { "sku": "SM-F766BDBEAFA", "sources": [ "https://apps.bazaarvoice.com/deployments/samsung-en_za/main_site/production/en_ZA/bv.js", "https://apps.bazaarvoice.com/deployments/Samsung-EN_ZA/main_site/production/en_ZA/bv.js" ] } }; const siteCode = els.siteCode ? els.siteCode.value : location.pathname.split('/')[1]; const { sku } = bvLocalData[siteCode] || {}; const bvScripSrcArr = bvLocalData[siteCode] ? bvLocalData[siteCode].sources : null; if (!bvScripSrcArr || bvScripSrcArr.length === 0 || !bvScripSrcArr.some((src) => !!src)) { eventList.hideReviews(); return; } const bvReviewWrapper = document.createElement('div'); bvReviewWrapper.classList.add('features-reviews-summary__bv'); bvReviewWrapper.setAttribute('data-bv-show', 'rating_summary'); bvReviewWrapper.setAttribute('data-bv-productid', sku); const bvOutWrapper = document.createElement('div'); bvOutWrapper.classList.add('features-reviews-out__bv'); bvOutWrapper.setAttribute('id', 'bvoutSummary'); bvOutWrapper.setAttribute('data-bv-show', 'reviews'); bvOutWrapper.setAttribute('data-bv-productid', sku); els.kvReviewRating && els.kvReviewRating.appendChild(bvReviewWrapper); els.reviewsInner && els.reviewsInner.appendChild(bvOutWrapper); bvScripSrcArr.forEach((src) => { const bvScript = document.createElement('script'); bvScript.src = src; els.reviewsInner.appendChild(bvScript); }); eventHandler.bvLoadObserver(); }, bvLoadObserver: function () { eventHandler.bvRatingSummaryAdded(); eventHandler.bvOutContainerAdded(); }, bvRatingSummaryAdded: function () { if (!els.kvReviewRating) return; const bvReviewRapper = document.querySelector('.features-reviews-summary__bv'); let addedRatingStarsCount = 0; const reviewSummaryObserver = new MutationObserver((mutationList) => { // Detect BV Review summary appended for (const mutation of mutationList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'svg') { addedRatingStarsCount += 1; if (addedRatingStarsCount { // When bvoutSummary initialized const ratingContent = shadowRoot.querySelector(bvSelector.out.ratingContent); if (!isAddedBVCloneEls) { if (!ratingContent) return; const reviewStyleEl = shadowRoot.querySelector('style'); const bvReviewsTitle = shadowRoot.querySelector('.gztyek'); bvEventList.appendReviewStyle(reviewStyleEl); bvEventList.removeBvOutTitle(bvReviewsTitle); bvEventList.setReviewsInitialHeight(); } for (const mutation of mutationList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { // Detect BV container height change if (!isLoadedBvImage && node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'img') { node.addEventListener('load', () => { eventList.responsive(); isLoadedBvImage = true; }); } // Detect bvoutSummary loaded Stars SVG if (!isLoadedBvStars && node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'svg') { addedOutStarsCount += 1; if (addedOutStarsCount rule.cssText).join('\n'); // clone BV CSS and append by document head const externalStyle = document.createElement('style'); externalStyle.textContent = styleText; document.head.appendChild(externalStyle); } }, removeBvOutTitle: function (titleEl) { titleEl?.remove(); }, setKvReviewsCTA: function (_addedBvData) { els.seeReviewsAnchor && els.seeReviewsAnchor.remove(); const { starsEl, avg, numReviews } = _addedBvData; els.kvReviewAnchor.insertBefore(starsEl, els.kvReviewAnchor.firstChild); els.kvReviewAvg.textContent = avg; els.kvReviewNumText.textContent = numReviews; eventList.showKvReviewCta(); }, clickReviewCta: function (e) { e.preventDefault(); const isClose = els.reviewsContent.style.height == '0px' || els.reviewsContent.style.height == 0; function goToReviewsSection() { const pdGFloatingNav = document.querySelector('.pd-g-floating-nav'); let navHeight = utils.getNavHeight(); if (navHeight === pdGFloatingNav.clientHeight && pdGFloatingNav.classList.contains('.floating-navigation--fixed')) { navHeight = 0; } const goToReviewScrollY = els.section.getBoundingClientRect().top - navHeight + window.scrollY; window.scrollTo(0, goToReviewScrollY); els.reviewsContent.removeEventListener('transitionend', goToReviewsSection); } if (isClose) { els.reviewsOpener.click(); els.reviewsContent.addEventListener('transitionend', goToReviewsSection); } else { goToReviewsSection(); } }, checkBvDatas: function () { if (!isBvRatingSummaryLoaded || !isBvOutSummaryLoaded) return; const ratingSummaryData = addedBvData.ratingSummary; const outSummaryData = addedBvData.outSummary; const hasRatingSummaryData = ratingSummaryData.starsEl && ratingSummaryData.avg && ratingSummaryData.numReviews !== '(0)'; const hasOutSummaryData = outSummaryData.starsEl && outSummaryData.avg && outSummaryData.numReviews !== '(0)'; const targetReviewsData = hasRatingSummaryData && !ratingSummaryData.isAdded ? ratingSummaryData : hasOutSummaryData && !outSummaryData.isAdded ? outSummaryData : null; if (targetReviewsData) { eventList.setAccordion(); this.setKvReviewsCTA(targetReviewsData); targetReviewsData.isAdded = true; } else { eventList.hideReviews(); } } } return { init: init } })(); })(); (function () { window.flagship = window.flagship || {}; window.flagship.features = window.flagship.features || {}; window.flagship.features.selfie = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize; let els = {}, prevDevice = null, currDevice = resize.checkResolution(); const init = function () { els.section = document.querySelector('.features-selfie'); els.fixedTrack = els.section.querySelector('.js-fixed-track'); if (!!els.section) { setElements(); bindEvents(); } }; const setElements = function () { els.fixedInner = els.section.querySelector('.js-fixed-inner'); els.selfieVisualWrap = els.section.querySelector('.js-selfie-wrap'); els.selfieVisual = els.section.querySelector('.js-selfie-visual'); els.selfieDevice = els.section.querySelectorAll('.js-selfie-device'); els.selfieVisualImg = els.section.querySelector('div.js-selfie-visual img'); }; const bindEvents = function () { resize.add(eventList.resize); fixedEvents.checkBrokenFixed(); if (!els.section.classList.contains('is-broken-fixed')) { fixedEvents.set(); fixedEvents.setTrack(); eventHandler.scroll(); } }; const eventHandler = { scroll: function () { window.addEventListener('scroll', fixedEvents.setTrack); } }; const eventList = { resize: function () { currDevice = resize.checkResolution(); fixedEvents.checkBrokenFixed(); if (currDevice != prevDevice) { if (!els.section.classList.contains('.is-broken-fixed')) { fixedEvents.set(); fixedEvents.setTrack(); } prevDevice = currDevice; } }, guiImagesActive: function (progress) { let maskChangeProgress = resize.checkResolution().indexOf('mobile') > -1 ? 61 : 30 if (progress > maskChangeProgress) { if (!els.selfieVisualWrap.classList.contains('is-change')) { els.selfieVisualWrap.classList.add('is-change'); } } else { els.selfieVisualWrap.classList.remove('is-change'); } }, hashtagAdd: function (progress) { if (progress > 90) { if (!els.selfieVisualWrap.classList.contains('is-hash')) { els.selfieVisualWrap.classList.add('is-hash'); } } else { els.selfieVisualWrap.classList.remove('is-hash'); } } }; const fixedEvents = { set: function () { if (els.fixedTrack.scene == null) { els.fixedTrack.scene = SCROLLER({ trackElement: els.fixedTrack, fixedElement: els.fixedInner, useFixed: true, useFixedStyle: false, trackHeight: 2, resize: utils.detector.isTouchDevice ? false : true }); } }, setTrack: function () { els.fixedTrack.scene.trackAnimation(function () { let progress = this.progress; eventList.guiImagesActive(progress); eventList.hashtagAdd(progress); if (resize.checkResolution().indexOf('mobile') > -1) { fixedEvents.mobileAnimation(progress); } else { fixedEvents.notMobileAnimation(progress); } }); }, notMobileAnimation: function (progress) { //device width let deviceWidth1 = 74, deviceWidth2 = 74, deviceWidth3 = 50.5 //visual masksize let svgMaskSize1 = 120, svgMaskSize2 = 74.2, svgMaskSize3 = 50.5 //visual img width let visualImgWidth = 100, visualImgWidth2 = 71, visualImgWidth3 = 48.4 // device let deviceScale = utils.calRange({ targetValue: deviceWidth2 - deviceWidth1, progress: progress, startPoint: 1, endPoint: 30 }); //visual mask size let maskSize1 = utils.calRange({ targetValue: svgMaskSize1 - svgMaskSize2, progress: progress, startPoint: 1, endPoint: 30 }); let maskSize2 = utils.calRange({ targetValue: svgMaskSize2 - svgMaskSize3, progress: progress, startPoint: 31, endPoint: 75 }); //calRange visual let visualWidth = utils.calRange({ targetValue: visualImgWidth - visualImgWidth2, progress: progress, startPoint: 1, endPoint: 30 }); let visualWidth2 = utils.calRange({ targetValue: visualImgWidth2 - visualImgWidth3, progress: progress, startPoint: 31, endPoint: 75 }); TweenMax.to(els.selfieVisual, 0, { maskSize: (svgMaskSize1 - maskSize1 - maskSize2) + '%', }); TweenMax.to(els.selfieDevice, 0, { width: (deviceWidth1 + deviceScale - maskSize2) + '%', }); TweenMax.to(els.selfieVisualImg, 0, { width: (visualImgWidth - visualWidth - visualWidth2) + '%' }); }, mobileAnimation: function (progress) { //visual masksize let moSvgMaskSize1 = 200, moSvgMaskSize2 = 160, moSvgMaskSize3 = 95, moSvgMaskSize4 = 80 //device size let moDeviceSize = 95, moDeviceSize2 = 80 //visual img width let moVisualImgWidth = 160, moVisualImgWidth2 = 91.2, moVisualImgWidth3 = 77 //device mask size let visualCrop1 = utils.calRange({ targetValue: moSvgMaskSize1 - moSvgMaskSize2, progress: progress, startPoint: 1, endPoint: 20 }); let visualCrop2 = utils.calRange({ targetValue: moSvgMaskSize2 - moSvgMaskSize3, progress: progress, startPoint: 21, endPoint: 60 }); let visualCrop3 = utils.calRange({ targetValue: moSvgMaskSize3 - moSvgMaskSize4, progress: progress, startPoint: 61, endPoint: 100 }); //device size(width) let deviceWidth = utils.calRange({ targetValue: moDeviceSize - moDeviceSize2, progress: progress, startPoint: 61, endPoint: 100 }); // img size let visualWidth = utils.calRange({ targetValue: moVisualImgWidth - moVisualImgWidth2, progress: progress, startPoint: 21, endPoint: 60 }); let visualWidth2 = utils.calRange({ targetValue: moVisualImgWidth2 - moVisualImgWidth3, progress: progress, startPoint: 61, endPoint: 100 }); TweenMax.to(els.selfieVisual, 0, { maskSize: (moSvgMaskSize1 - visualCrop1 - visualCrop2 - visualCrop3) + 'vw', }); TweenMax.to(els.selfieVisualImg, 0, { width: (moVisualImgWidth - visualWidth - visualWidth2) + 'vw' }); TweenMax.to(els.selfieDevice, 0, { width: (moDeviceSize - deviceWidth) + '%' }); }, checkBrokenFixed: function () { const navHeight = resize.checkResolution().indexOf('mobile') > -1 ? window.innerHeight * 0.2666666667 : 96; const innerHeight = window.innerHeight - navHeight; const viewPortRatio = window.innerWidth / innerHeight; const isCdevice = document.documentElement.classList.contains('isCdevice'); const agent = navigator.userAgent; const agentDataList = agent.split(' '); agentDataList.forEach((data) => { if (data.indexOf('Samsung') > -1) { if (data.split('/')[1] -1)) { if (viewPortRatio > 2.8 || viewPortRatio -1) && !document.documentElement.classList.contains('low_network')) { if (els.section.classList.contains('is-broken-fixed') && (!els.section.classList.contains('old-samsung') && !isCdevice)) { els.section.classList.remove('is-broken-fixed'); } } } } return { init: init, } })(); })(); (function () { window.flagship.features.storage = (function () { const utils = window.flagship.common.utils; let els = {}; const init = function () { els.section = document.querySelector('.features-storage'); if (els.section != null) { bindEvents(); } }; const bindEvents = function () { eventHandler.openAnchor(); }; const eventHandler = { openAnchor: function () { window.addEventListener('DOMContentLoaded', eventList.openHash); window.addEventListener('hashchange', eventList.openHash); } }; const eventList = { openHash: function () { if (window.location.hash != '') { let hash = location.hash.split('#')[1], hashSection = document.querySelector('#contents #' + hash), hashTimeout = null; if (hash !== 'storage') return; clearTimeout(hashTimeout); if (hashSection) { hashTimeout = setTimeout(function () { let sectionTop = hashSection.getBoundingClientRect().top, navHeight = utils.getNavHeight(), hashScroll = window.pageYOffset + sectionTop - navHeight, halfHeight = ((window.innerHeight - utils.getNavHeight() - els.section.offsetHeight) / 2); window.scrollTo(0, hashScroll - halfHeight); }, 300); } } } }; return { init: init } })(); })(); (function () { window.flagship = window.flagship || {}; window.flagship.features = window.flagship.features || {}; window.flagship.features.switchToGalaxy = (function () { const resize = window.flagship.common.resize, utils = window.flagship.common.utils; accordion = flagship.common.Accordion; let els = {}, prevDevice = resize.checkResolution(), currDevice = resize.checkResolution(); const init = function () { els.section = document.querySelector('.js-switch'); if (!!els.section) { setElements(); bindEvents(); } }; const setElements = function () { els.switchList = els.section.querySelector('.js-switch-list'); els.rotate = els.section.querySelector('.js-roate'); els.switchTexts = els.section.querySelectorAll('.js-switch-change'); }; const bindEvents = function () { resize.add(eventList.resize); eventHandler.load(); eventList.initText(); }; const eventHandler = { load: function () { window.addEventListener('load', function () { if (currDevice.indexOf('mobile') > -1) { eventList.setAccordion(); } }) } }; const eventList = { resize: function (currRes) { currDevice = currRes; if (currDevice != prevDevice) { eventList.changeText(); eventList.checkAccordionInit(); prevDevice = currDevice; } }, checkAccordionInit: function () { if (currDevice.indexOf('mobile') > -1) { if (!els.accordion) { const items = els.switchList.querySelectorAll('.js-switch-item'); items[0].classList.add('is-open'); eventList.setAccordion(); } } else { if (els.accordion) { eventList.destroyAccordion(); } } }, setAccordion: function () { els.accordion = new window.flagship.common.accordion({ wrap: els.switchList, classList: { item: 'js-switch-item', button: 'js-switch-open', contents: 'js-switch-answer', activeClass: 'is-open' }, openType: 'single', open: { start: function (target) { let targetInnerCta = target.querySelector('.js-featue-cta'); if (targetInnerCta) targetInnerCta.addEventListener('click', accessibility.moveFocus); setTagging.close(target); } }, close: { start: function (target) { setTagging.open(target); } } }); els.accordion.init(); }, changeText: function () { els.switchTexts.forEach(text => { const headTitle = text.querySelector('.common-text'); const buttonTitle = text.nextElementSibling.querySelector('.common-text'); if (currDevice.indexOf('mobile') > -1) { buttonTitle.innerText = text.titleText; headTitle.innerText = text.emptyText; } else { headTitle.innerText = text.titleText; buttonTitle.innerText = text.emptyText; } }); }, initText: function () { els.switchTexts.forEach(text => { text.titleText = text.querySelector('.common-text').innerText; text.emptyText = ''; const headTitle = text.querySelector('.common-text'); const buttonTitle = text.nextElementSibling.querySelector('.common-text'); if (currDevice.indexOf('mobile') > -1) { headTitle.innerText = text.emptyText; buttonTitle.innerText = text.titleText; } }); }, destroyAccordion: function () { if (els.accordion) { els.accordion.destroy(); els.accordion = null; } } }; const setTagging = { open: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('close', 'open')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('close', 'open')); } }, close: function (target) { if (target.hasAttribute('an-tr')) { let dataOmni = target.getAttribute('an-tr').toLowerCase(); target.setAttribute('an-tr', dataOmni.replace('open', 'close')); } if (target.hasAttribute('an-la')) { let gaLa = target.getAttribute('an-la').toLowerCase(); target.setAttribute('an-la', gaLa.replace('open', 'close')); } } }; const accessibility = { moveFocus: function (e) { if (desktopStatus) return; if (this.getAttribute('href').indexOf('#') > -1) { e.preventDefault(); let sectionId = this.getAttribute('href'), section = document.querySelector(`${sectionId}`), sectionTop = section.getBoundingClientRect().top, movePosition = (sectionTop + window.pageYOffset) - utils.getNavHeight(), clickable = section.querySelectorAll('a, button'), title = section.querySelector('h2') || section.querySelector('h3'); if (!!title) { let _focusOut = function () { title.removeAttribute('tabindex'); title.removeEventListener('focusout', _focusOut); }; title.addEventListener('focusout', _focusOut); title.setAttribute('tabindex', 0); title.focus(); } else { clickable[0].focus(); } window.scrollTo(0, movePosition); } } }; return { init: init } })(); })(); (function () { window.flagship = window.flagship || {}; window.flagship.features = window.flagship.features || {}; window.flagship.features.unveiling = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize; let els = {}, obj = {}, wheelDirection, currDevice = resize.checkResolution(), prevDevice = null, isPointerDown = false, isMobile = true, isTablet = window.innerWidth >= 535 && window.innerWidth 18) { if (!els.headline.classList.contains('is-active')) { els.headline.classList.add('is-active'); }; } else if (progress 30) { TweenMax.to(els.headline, 0, { opacity: 1 - fadeOut }); TweenMax.to(els.videoArea, 0, { opacity: videoFadeIn }); } if (isTablet && progress > 14) { TweenMax.to(els.videoArea, 0, { opacity: videoFadeIn }); } }, setDescInteraction: function (progress) { let opacityValue1 = !isMobile ? 62 : 43; let opacityValue2 = !isMobile ? 70 : 50; if (isTablet) { if (progress >= 58) { if (!els.desc.classList.contains('is-active')) { els.desc.classList.add('is-active'); TweenMax.to(els.desc, 1, { opacity: 1 }); }; } else { if (els.desc.classList.contains('is-active')) { els.desc.classList.remove('is-active'); TweenMax.to(els.desc, .5, { opacity: 0 }); }; }; } else { if (progress > opacityValue1) { if (!els.desc.classList.contains('is-active')) { els.desc.classList.add('is-active'); TweenMax.to(els.desc, 1, { opacity: 1 }); }; } else if (progress 72 && !isMobile) { const fadeOut = eventList.getCalRange(1, progress, 72, 80); TweenMax.to(els.desc, 0, { opacity: 1 - fadeOut }) } } }, setVideoTrackEvent: function (progress) { const fadeOut = eventList.getCalRange(1, progress, 72, 80); if (isMobile) { if (progress > 25 && progress 70) { TweenMax.to(els.videoOpacity, 1, { opacity: 1 }); TweenMax.to(els.video, .5, { opacity: 0 }); } } else if (isTablet) { if (progress > 25) { TweenMax.to(els.video, 1, { opacity: 1 }); } else { TweenMax.to(els.video, .3, { opacity: 0 }); } } else { if (progress > 33 && progress = 72) { TweenMax.to(els.video, 0, { opacity: 1 - fadeOut }); TweenMax.to(els.videoOpacity, 0, { opacity: 1 - fadeOut }); if (!els.videoWrap.controller.classList.contains('is-hidden')) els.videoWrap.controller.classList.add('is-hidden'); } else { TweenMax.to(els.videoOpacity, 1, { opacity: 1 }); TweenMax.to(els.video, .5, { opacity: 0 }); } } eventList.resetVideoEvent(progress); }, resetVideoEvent: function (progress) { if (isMobile) { if (progress { els.videoWrap.classList.remove('is-started'); els.videoWrap.classList.remove('is-paused'); els.videoWrap.classList.remove('is-ended'); els.video.currentTime = 0; }, 300); } } else if (isTablet) { if (progress 30 && els.videoWrap.classList.contains('is-paused')) { els.videoWrap.classList.remove('is-paused') } } else { if (progress 47 && els.videoWrap.classList.contains('is-paused')) { els.videoWrap.classList.remove('is-paused') } } }, checkDevice: function () { if (currDevice == 'mobile' || currDevice == 'mobileS') { isMobile = true; } else { isMobile = false; } }, resize: function (currRes) { currDevice = currRes; if (currDevice != prevDevice) { eventList.checkDevice(); prevDevice = currDevice; } } } const accessibility = { focus: function (e) { if (isPointerDown) return; let self = this; els.desc.style.translateY = 0; els.desc.style.opacity = 1; if (self == els.videoWrap.controller) { setTimeout(() => { self.scrollIntoView(false); }, 15) els.videoOpacity.style.opacity = 1; } } } return { init: init, }; })(); })(); (function () { window.flagship.features.howtoPopup = (function () { const utils = window.flagship.common.utils, resize = window.flagship.common.resize, Swiper = window.flagship.Swiper; let els = {}, currDevice = resize.checkResolution(), prevDevice = null, currOpener = null; const init = function () { els.layerPopup = document.querySelector('.js-howto-popup'); if (!!els.layerPopup) { setElements(); bindEvents(); } }; const setElements = function () { els.contents = document.querySelector('#contents'); els.openCtas = document.querySelectorAll('.js-howto-popup-opener'); els.popupData = document.querySelectorAll('.js-howto-popup-data'); // popup content els.popupTemplate = document.querySelector('.js-howto-template'); els.closeCta = document.querySelectorAll('.js-howto-popup-close-cta'); els.ytIframe = els.layerPopup.querySelector('iframe'); els.ytDesc = els.layerPopup.querySelector('.js-howto-popup-youtube-desc'); els.dimmed = els.layerPopup.querySelector('.js-howto-popup-dimmed'); // swiper els.swiperContainer = els.layerPopup.querySelector('.js-howto-popup-swiper'); els.featureTagging = els.swiperContainer.getAttribute('data-tagging-feature'); els.swiperWrapper = els.swiperContainer.querySelector('.js-howto-popup-swiper-wrapper'); els.navigationWrap = els.layerPopup.querySelector('.js-arrow-wrap'); els.swiperNextArrow = els.layerPopup.querySelector('.js-howto-next'); els.swiperPrevArrow = els.layerPopup.querySelector('.js-howto-prev'); els.indicationWrap = els.swiperContainer.querySelector('.js-howto-popup-pagination-wrap'); els.indication = els.swiperContainer.querySelector('.js-howto-popup-pagination'); // template let tempPopupThumb = []; for (let i = 0; i { const howtoAtrr = cta.getAttribute('data-howto-popup-slide'); els.popupThumb.forEach((thumb) => { if (thumb.getAttribute('data-howto-popup-slide') === howtoAtrr) { thumb.openerCta = cta; thumb.button = thumb.querySelector('button'); cta.thumb = thumb; } }); }); }, setYoutube: function (target) { let opener = target.openerCta, ytSrc = 'htt' + 'ps://www.youtube.com/embed/' + opener.getAttribute('data-youtube-id') + '?wmode=opaque&rel=0&enablejsapi=1&version=3&autoplay=1', ytTitle = opener.getAttribute('data-youtube-title'), ytBlind = opener.querySelector('.sr-only').innerHTML; els.ytIframe.setAttribute('src', ytSrc); els.ytIframe.setAttribute('title', ytTitle); els.ytDesc.innerHTML = ytBlind; let oldActive = els.swiperContainer.querySelector('.js-howto-popup-swiper-slide.is-active'); if (!!oldActive) { oldActive.classList.remove('is-active'); oldActive.button.removeAttribute('title'); } opener.thumb.classList.add('is-active'); accessibility.setTitle(opener.thumb.button); }, removeYoutube: function () { els.ytIframe.removeAttribute('src'); els.ytIframe.title = ''; els.ytDesc.innerHTML = ''; accessibility.removeTitle(els.popupThumb); }, resize: function (currRes) { currDevice = currRes; if (prevDevice != currDevice) { swiperEventList.destroy(); swiperEventList.activeCheck(); swiperEventList.isOpendSlide(); prevDevice = currDevice; if (els.swiperContainer.swiper && els.layerPopup.classList.contains('is-open')) { for (let i = 0; i `; } }, a11y: false, }); els.swiperContainer.swiper.on('init', swiperEventList.init); els.swiperContainer.swiper.on('slideChange', swiperEventList.slideChange); els.swiperContainer.swiper.on('paginationUpdate', swiperEventList.paginationUpdate); els.swiperContainer.swiper.init(); } }, destroy: function () { if (els.swiperContainer.swiper != null) { els.swiperContainer.swiper.navigation.destroy(true); els.swiperContainer.swiper.destroy(true); els.swiperContainer.swiper = null; } }, init: function () { let self = this, notification = self.el.querySelector('.swiper-notification'); if (!!notification) self.el.removeChild(notification); }, paginationUpdate: function () { const bullets = this.pagination.bullets; const slides = this.slides; let arrSlidesTitle = []; for (let i = 0; i -1) { button.setAttribute('aria-label', `${LOCAL_VARI.slide}${i + 1}${selected}: ${arrSlidesTitle[i]}, ${arrSlidesTitle[i + 1]}`); } else { button.setAttribute('aria-label', `${LOCAL_VARI.slide}${i + 1}${selected}: ${arrSlidesTitle[i]}, ${arrSlidesTitle[i + 1]}, ${arrSlidesTitle[i + 2]}, ${arrSlidesTitle[i + 3]}`); } } }, slideChange: function () { accessibility.slide(); accessibility.slideArrow(els.swiperContainer.swiper); }, activeCheck: function () { let isSlide = ((currDevice.indexOf('mobile') > -1) && (els.popupThumb.length >= 3)) || ((currDevice.indexOf('desktop') > -1 || currDevice == 'tablet') && (els.popupThumb.length >= 5)); if (isSlide) { els.swiperWrapper.style.justifyContent = ''; swiperEventList.set(); els.navigationWrap.style.display = ''; els.indicationWrap.style.display = ''; } else { swiperEventList.destroy(); els.swiperWrapper.style.justifyContent = 'center'; els.navigationWrap.style.display = 'none'; els.indicationWrap.style.display = 'none'; } }, isOpendSlide: function () { if (els.swiperContainer.swiper != null) { let buttonIndex; if (currOpener != null) { for (let i = 0; i -1 ? 2 : 4; let getPerviewIndex = function () { return slidePerviewValue - 1; } if (els.swiperContainer.swiper) { for (let i = 0; i = els.swiperContainer.swiper.activeIndex && i -1) { if (document.getElementsByClassName('nv00-gnb-v3') && document.getElementsByClassName('nv00-gnb-v3')[0]) { document.getElementsByClassName('nv00-gnb-v3')[0].style.display = 'none' } if (document.getElementsByClassName('nv00-gnb-v4') && document.getElementsByClassName('nv00-gnb-v4')[0]) { document.getElementsByClassName('nv00-gnb-v4')[0].style.display = 'none' } if (document.getElementsByClassName('footer') && document.getElementsByClassName('footer')[0]) { document.getElementsByClassName('footer')[0].style.display = 'none' } if ( document.getElementsByClassName("lvc-popup-stream-container") && document.getElementsByClassName("lvc-popup-stream-container")[0] ) { document.getElementsByClassName( "lvc-popup-stream-container" )[0].style.display = "none"; } if (document.getElementById("header")) { document.getElementById("header").style.display = "none"; } if ( document.getElementsByClassName("idz_online_mweb-container") && document.getElementsByClassName("idz_online_mweb-container")[0] ) { document.getElementsByClassName( "idz_online_mweb-container" )[0].style.display = "none"; } } });