PanoView.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. <template>
  2. <div class="pano-view">
  3. <!-- <div id="pano" /> -->
  4. <iframe
  5. ref="panoIframe"
  6. :src="iframeSrc"
  7. frameborder="0"
  8. />
  9. <button
  10. class="return-home"
  11. @click="router.push({
  12. name: 'HomeView',
  13. })"
  14. />
  15. <CameraDesc
  16. v-if="isShowCameraDesc"
  17. class="camera-desc"
  18. @close="isShowCameraDesc = false"
  19. />
  20. <CharacterDesc
  21. v-if="isShowCharacterDesc"
  22. class="character-desc"
  23. @close="isShowCharacterDesc = false"
  24. />
  25. <div
  26. class="character-wrap"
  27. draggable="false"
  28. >
  29. <button
  30. class="name"
  31. @click="isShowCharacterDesc = true"
  32. >
  33. <span>趙孟頫</span>
  34. </button>
  35. <div
  36. class="character-frames-wrapper"
  37. @click="onClickCharacter"
  38. >
  39. <img
  40. v-show="animationType === 1"
  41. class="default-frames"
  42. src="@/assets/images/A1-min.png"
  43. alt=""
  44. draggable="false"
  45. >
  46. <img
  47. v-show="animationType === 2"
  48. class="frames frames-2"
  49. :class="{
  50. animating: isCharacterSpecialMoving,
  51. state1: isCharacterSpecialMoving === 0,
  52. state2: isCharacterSpecialMoving === 1,
  53. }"
  54. src="@/assets/images/A2-min.png"
  55. alt=""
  56. draggable="false"
  57. >
  58. <img
  59. v-show="animationType === 3"
  60. class="frames frames-3"
  61. :class="{
  62. animating: isCharacterSpecialMoving,
  63. state1: isCharacterSpecialMoving === 0,
  64. state2: isCharacterSpecialMoving === 1,
  65. }"
  66. src="@/assets/images/A3-min.png"
  67. alt=""
  68. draggable="false"
  69. >
  70. </div>
  71. <img
  72. class="btn-track"
  73. :src="require(`@/assets/images/people-btn-track-${sceneIdx + 1}.png`)"
  74. alt=""
  75. draggable="false"
  76. >
  77. <button
  78. class="one btn-on-track"
  79. @click="showingContentIdx = 1"
  80. >
  81. <span>{{ btnOnTrack1Name }}</span>
  82. </button>
  83. <button
  84. class="two btn-on-track"
  85. @click="showingContentIdx = 2"
  86. >
  87. <span>{{ btnOnTrack2Name }}</span>
  88. </button>
  89. <button
  90. class="three btn-on-track"
  91. @click="showingContentIdx = 3"
  92. >
  93. <span>{{ btnOnTrack3Name }}</span>
  94. </button>
  95. <button
  96. class="four btn-on-track"
  97. @click="router.push({
  98. name: 'RelicList',
  99. query: {
  100. sceneIdx: route.query.sceneIdx,
  101. cameraIdx: route.query.cameraIdx,
  102. }
  103. })"
  104. >
  105. <span>文物长卷</span>
  106. </button>
  107. </div>
  108. <div class="camera-list">
  109. <button
  110. v-for="(item, idx) in currentCameraList"
  111. :key="idx"
  112. class="camera-entry"
  113. :class="{
  114. active: idx === (mouseEnterCameraItemIdx === -1 ? cameraIdx : mouseEnterCameraItemIdx)
  115. }"
  116. @mouseenter="mouseEnterCameraItemIdx = idx"
  117. @mouseleave="mouseEnterCameraItemIdx = -1"
  118. @click="router.push({
  119. name: route.name,
  120. query:{
  121. sceneIdx: route.query.sceneIdx,
  122. cameraIdx: idx,
  123. }
  124. })"
  125. >
  126. <span>{{ item.name }}</span>
  127. <img
  128. class="bg-normal"
  129. :src="require(`@/assets/images/camera-list-item-bg-${sceneIdx + 1}.png`)"
  130. alt=""
  131. draggable="false"
  132. >
  133. <img
  134. class="bg-active"
  135. :src="require(`@/assets/images/camera-list-item-bg-active-${sceneIdx + 1}.png`)"
  136. alt=""
  137. draggable="false"
  138. >
  139. </button>
  140. <button
  141. class="next-scene"
  142. @click="onClickNextScene"
  143. />
  144. </div>
  145. <CameraContent1
  146. v-if="showingContentIdx === 1"
  147. class="camera-content"
  148. @close="showingContentIdx = 0"
  149. />
  150. <CameraContent2
  151. v-if="showingContentIdx === 2"
  152. class="camera-content"
  153. @close="showingContentIdx = 0"
  154. />
  155. <CameraContent3
  156. v-if="showingContentIdx === 3"
  157. class="camera-content"
  158. @close="showingContentIdx = 0"
  159. />
  160. <RelicDetailForHotspot
  161. v-if="isShowHotspotDetail"
  162. :relic-info="hotspotRelicInfo"
  163. @close="isShowHotspotDetail = false"
  164. />
  165. <transition name="fade-in-out-slow">
  166. <video
  167. v-show="isShowEffectVideo1"
  168. ref="sceneChangeEffectVideo1"
  169. class="sceneChangeEffectVideo"
  170. load="lazy"
  171. src="@/assets/videos/scene-change-effect-1.mp4"
  172. playsinline
  173. webkit-playsinline="true"
  174. x5-video-player-type="h5"
  175. @ended="onEffectVideoEnd"
  176. />
  177. </transition>
  178. <transition name="fade-in-out-slow">
  179. <video
  180. v-show="isShowEffectVideo2"
  181. ref="sceneChangeEffectVideo2"
  182. class="sceneChangeEffectVideo"
  183. src="@/assets/videos/scene-change-effect-2.mp4"
  184. playsinline
  185. webkit-playsinline="true"
  186. x5-video-player-type="h5"
  187. @ended="onEffectVideoEnd"
  188. />
  189. </transition>
  190. <transition name="cloud-top">
  191. <img
  192. v-if="isShowEffectCloud"
  193. class="cloud cloud-top"
  194. src="@/assets/images/cloud-top.png"
  195. alt=""
  196. draggable="false"
  197. >
  198. </transition>
  199. <transition name="cloud-left-bottom">
  200. <img
  201. v-if="isShowEffectCloud"
  202. class="cloud-left-bottom"
  203. src="@/assets/images/cloud-left-bottom.png"
  204. alt=""
  205. draggable="false"
  206. >
  207. </transition>
  208. <transition name="cloud-right-bottom">
  209. <img
  210. v-if="isShowEffectCloud"
  211. class="cloud-right-bottom"
  212. src="@/assets/images/cloud-right-bottom.png"
  213. alt=""
  214. draggable="false"
  215. >
  216. </transition>
  217. </div>
  218. </template>
  219. <script setup>
  220. import { ref, computed, watch, onMounted, nextTick, watchEffect } from "vue"
  221. import { useRoute, useRouter, onBeforeRouteUpdate } from "vue-router"
  222. import { useStore } from "vuex"
  223. import * as krfn from "@/libs/pano-core/index.js"
  224. import CameraDesc from '@/components/CameraDesc.vue'
  225. import CharacterDesc from '@/components/CharacterDesc.vue'
  226. import { defineAsyncComponent } from 'vue'
  227. import sceneTree from '/public/sceneTree.js'
  228. import RelicDetailForHotspot from '@/components/RelicDetailForHotspot.vue'
  229. const btnReturnHomeImgUrl = computed(() => {
  230. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/btn-return-home-${sceneIdx.value + 1}.png`) + ')'
  231. })
  232. const btnReturnHomeActiveImgUrl = computed(() => {
  233. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/btn-return-home-active-${sceneIdx.value + 1}.png`) + ')'
  234. })
  235. const btnOnTrack1ImgUrl = computed(() => {
  236. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-1.png`) + ')'
  237. })
  238. const btnOnTrack1ActiveImgUrl = computed(() => {
  239. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-1-active.png`) + ')'
  240. })
  241. const btnOnTrack2ImgUrl = computed(() => {
  242. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-2.png`) + ')'
  243. })
  244. const btnOnTrack2ActiveImgUrl = computed(() => {
  245. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-2-active.png`) + ')'
  246. })
  247. const btnOnTrack3ImgUrl = computed(() => {
  248. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-3.png`) + ')'
  249. })
  250. const btnOnTrack3ActiveImgUrl = computed(() => {
  251. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-3-active.png`) + ')'
  252. })
  253. const btnOnTrack4ImgUrl = computed(() => {
  254. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-4.png`) + ')'
  255. })
  256. const btnOnTrack4ActiveImgUrl = computed(() => {
  257. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-4-active.png`) + ')'
  258. })
  259. const cameraListBgUrl = computed(() => {
  260. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-list-bg-${sceneIdx.value + 1}.png`) + ')'
  261. })
  262. const btnOnTrack1Name = computed(() => {
  263. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[0]
  264. })
  265. const btnOnTrack2Name = computed(() => {
  266. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[1]
  267. })
  268. const btnOnTrack3Name = computed(() => {
  269. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[2]
  270. })
  271. let CameraContent1 = defineAsyncComponent(() =>
  272. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-1.vue`)
  273. )
  274. let CameraContent2 = defineAsyncComponent(() =>
  275. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-2.vue`)
  276. )
  277. let CameraContent3 = defineAsyncComponent(() =>
  278. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-3.vue`)
  279. )
  280. onBeforeRouteUpdate((to, from) => {
  281. console.log('to: ', to)
  282. if (to.name === route.name) {
  283. CameraContent1 = defineAsyncComponent(() =>
  284. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-1.vue`)
  285. )
  286. CameraContent2 = defineAsyncComponent(() =>
  287. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-2.vue`)
  288. )
  289. CameraContent3 = defineAsyncComponent(() =>
  290. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-3.vue`)
  291. )
  292. }
  293. })
  294. const {
  295. windowSizeInCssForRef,
  296. windowSizeWhenDesignForRef,
  297. } = useSizeAdapt()
  298. const route = useRoute()
  299. const router = useRouter()
  300. const store = useStore()
  301. const sceneIdx = computed(() => {
  302. return Number(route.query.sceneIdx)
  303. })
  304. const cameraIdx = computed(() => {
  305. return Number(route.query.cameraIdx)
  306. })
  307. const isCharacterSpecialMoving = ref(0)
  308. const animationType = ref(1)
  309. const isShowCameraDesc = ref(false)
  310. const isShowCharacterDesc = ref(false)
  311. const showingContentIdx = ref(0)
  312. function onClickCharacter() {
  313. // isShowCameraDesc.value = true
  314. if (!isCharacterSpecialMoving.value) {
  315. animationType.value = Math.floor(Math.random() * 2) + 2
  316. let duration = 0
  317. switch (animationType.value) {
  318. case 2:
  319. duration = 2000
  320. break
  321. case 3:
  322. duration = 1500
  323. break
  324. default:
  325. break
  326. }
  327. setTimeout(() => {
  328. isCharacterSpecialMoving.value = 1
  329. setTimeout(() => {
  330. isCharacterSpecialMoving.value = 0
  331. animationType.value = 1
  332. }, duration)
  333. }, 200)
  334. }
  335. }
  336. const currentCameraList = computed(() => {
  337. return sceneTree[sceneIdx.value].cameraList
  338. })
  339. const mouseEnterCameraItemIdx = ref(-1)
  340. const sceneChangeEffectVideo1 = ref(null)
  341. const sceneChangeEffectVideo2 = ref(null)
  342. const isShowEffectVideo1 = ref(false)
  343. const isShowEffectVideo2 = ref(false)
  344. const isShowEffectCloud = ref(false)
  345. function onClickNextScene() {
  346. if (sceneIdx.value === 0) {
  347. isShowEffectVideo1.value = true
  348. setTimeout(() => {
  349. sceneChangeEffectVideo1.value.play()
  350. }, 1000)
  351. } else if (sceneIdx.value === 1) {
  352. isShowEffectVideo2.value = true
  353. setTimeout(() => {
  354. sceneChangeEffectVideo2.value.play()
  355. }, 1000)
  356. } else if (sceneIdx.value === 2) {
  357. router.push({
  358. name: 'EpilogueView',
  359. })
  360. }
  361. }
  362. function onEffectVideoEnd() {
  363. isShowEffectCloud.value = true
  364. router.push({
  365. name: route.name,
  366. query: {
  367. sceneIdx: Number(route.query.sceneIdx) + 1,
  368. cameraIdx: 0,
  369. }
  370. })
  371. setTimeout(() => {
  372. isShowEffectVideo1.value = false
  373. isShowEffectVideo2.value = false
  374. }, 1000)
  375. setTimeout(() => {
  376. isShowEffectCloud.value = false
  377. }, 2500)
  378. }
  379. const iframeSrc = process.env.VUE_APP_CLI_MODE === 'dev' ? 'http://192.168.0.27:8081/show.html?id=WK1730428603763576832&vr=fd720_CKI5Ly4eo&lang=zh' : 'https://houseoss.4dkankan.com/project/yzdyh-dadu/pano/show.html?id=WK1730428603763576832&vr=fd720_CKI5Ly4eo&lang=zh'
  380. const panoIframe = ref(null)
  381. watch(cameraIdx, (vNew) => {
  382. console.log('parent window: post message!')
  383. panoIframe.value.contentWindow.postMessage({
  384. msgName: 'change-scene',
  385. sceneId: store.getters.catalogTopology[sceneIdx.value].children[0].children[cameraIdx.value].id
  386. }, '*')
  387. }, {
  388. deep: true,
  389. })
  390. // window.addEventListener('message', (e) => {
  391. // console.log('parent window: received message!', e)
  392. // })
  393. const isShowHotspotDetail = ref(false)
  394. const hotspotRelicInfo = ref({})
  395. window.showHotspotDetail = function(hotspotInfo) {
  396. console.log('parent window: 展示热点详情')
  397. console.log(hotspotInfo)
  398. console.log(hotspotInfo.hotspotTitle)
  399. hotspotRelicInfo.value = hotspotInfo
  400. isShowHotspotDetail.value = true
  401. }
  402. /**
  403. * 全景图
  404. */
  405. function fixPanoData(panoData) {
  406. // 丢弃没有包含场景的二级分组
  407. let tmp = []
  408. panoData.scenes.forEach((item) => {
  409. panoData.catalogs.forEach((sub) => {
  410. if (item.category == sub.id) {
  411. if (tmp.indexOf(sub) < 0) {
  412. tmp.push(sub)
  413. }
  414. }
  415. })
  416. })
  417. tmp = utils.unique(tmp)
  418. panoData.catalogs = tmp
  419. // 丢弃没有包含二级分组的一级分组
  420. let rootmp = []
  421. tmp.forEach((item) => {
  422. panoData.catalogRoot.forEach((sub) => {
  423. sub.children = utils.unique(sub.children)
  424. if (sub.children.indexOf(item.id) > -1) {
  425. rootmp.push(sub)
  426. }
  427. })
  428. })
  429. rootmp = utils.unique(rootmp)
  430. // 一级分组按名称排序
  431. let sortArr = panoData.catalogRoot.map((item) => item.name)
  432. rootmp.sort((a, b) => {
  433. return sortArr.indexOf(a.name) - sortArr.indexOf(b.name)
  434. })
  435. // 各个一级分组的children去重,只留下有实际的二级分组相对应的那些children item。
  436. panoData.catalogRoot = rootmp.map((item) => {
  437. let temp = []
  438. item.children = utils.unique(item.children)
  439. item.children.forEach((sub) => {
  440. tmp.forEach((jj) => {
  441. if (jj.id == sub) {
  442. temp.push(sub)
  443. }
  444. })
  445. })
  446. return {
  447. ...item,
  448. children: temp,
  449. }
  450. })
  451. // 多余
  452. panoData.catalogs = tmp
  453. // 如果没有一级分组(一定也就没有二级分组)就创建一级分组和二级分组 有必要吗?
  454. let cid = "c_" + utils.randomWord(true, 8, 8)
  455. if (panoData.catalogRoot.length <= 0) {
  456. panoData.catalogRoot.push({
  457. id: "r_" + utils.randomWord(true, 8, 8),
  458. name: "全部场景",
  459. children: [cid],
  460. })
  461. }
  462. if (panoData.catalogs.length <= 0) {
  463. panoData.catalogs.push({
  464. id: cid,
  465. name: "默认二级分组",
  466. })
  467. }
  468. // 如果有初始场景,改为引用场景列表中对应的那个场景的js对象
  469. if (panoData.firstScene) {
  470. panoData.firstScene = panoData.scenes.find(
  471. (item) => item.sceneCode == panoData.firstScene.sceneCode
  472. )
  473. }
  474. }
  475. onMounted(() => {
  476. api.fetchPanoData('WK1730428603763576832').then((res) => {
  477. fixPanoData(res)
  478. store.commit('setPanoData', res)
  479. console.log('catalogTopology', store.getters.catalogTopology)
  480. })
  481. })
  482. </script>
  483. <style lang="less" scoped>
  484. *{
  485. user-select: none;
  486. }
  487. .pano-view{
  488. position: relative;
  489. height: 100%;
  490. >iframe{
  491. position: absolute;
  492. left: 0;
  493. top: 0;
  494. width: 100%;
  495. height: 100%;
  496. }
  497. >button.return-home{
  498. position: absolute;
  499. width: 77px;
  500. height: 77px;
  501. top: 43px;
  502. right: 51px;
  503. background-image: v-bind(btnReturnHomeImgUrl);
  504. background-size: cover;
  505. background-repeat: no-repeat;
  506. background-position: center center;
  507. &:hover{
  508. background-image: v-bind(btnReturnHomeActiveImgUrl);
  509. }
  510. }
  511. >.camera-desc{
  512. z-index: 5;
  513. }
  514. >.character-desc{
  515. z-index: 5;
  516. }
  517. >.character-wrap{
  518. position: absolute;
  519. left: 40px;
  520. bottom: 0;
  521. width: 300px;
  522. height: 452px;
  523. >button.name{
  524. position: absolute;
  525. top: 50px;
  526. left: 0;
  527. transform: translateX(-50%);
  528. width: 36px;
  529. height: 178px;
  530. z-index: 3;
  531. font-size: 23px;
  532. font-family: Source Han Serif SC, Source Han Serif SC;
  533. font-weight: 400;
  534. color: #43310E;
  535. line-height: 27px;
  536. letter-spacing: 7px;
  537. writing-mode: vertical-lr;
  538. background-image: url(@/assets/images/people-name-bg.png);
  539. background-size: contain;
  540. background-repeat: no-repeat;
  541. background-position: center center;
  542. >span{
  543. position: absolute;
  544. left: 45%;
  545. top: 50%;
  546. transform: translate(-50%, -50%);
  547. }
  548. }
  549. @frame-width: 256px;
  550. @frame-height: 512px;
  551. @duration-1: 3s;
  552. @frame-num-1: 72;
  553. @duration-2: 2s;
  554. @frame-num-2: 48;
  555. @duration-3: 1.5s;
  556. @frame-num-3: 36;
  557. >.character-frames-wrapper {
  558. position: absolute;
  559. left: 0;
  560. top: -60px;
  561. height: @frame-height;
  562. width: @frame-width;
  563. overflow: hidden;
  564. z-index: 1;
  565. cursor: pointer;
  566. >.default-frames{
  567. position: absolute;
  568. left: 0;
  569. height: 100%;
  570. animation-name: character-default-animation;
  571. animation-timing-function: steps(73, end);
  572. animation-duration: 3s;
  573. animation-iteration-count: infinite;
  574. }
  575. >.frames {
  576. position: absolute;
  577. height: 100%;
  578. transition-property: none;
  579. &.animating{
  580. transition-property: left;
  581. }
  582. &.state1 {
  583. left: 0;
  584. }
  585. }
  586. >.frames-2{
  587. transition-duration: @duration-2;
  588. transition-timing-function: steps(@frame-num-2 - 1, jump-end);
  589. &.state2 {
  590. left: calc(-100% * (@frame-num-2 - 1));
  591. }
  592. }
  593. >.frames-3{
  594. transition-duration: @duration-3;
  595. transition-timing-function: steps(@frame-num-3 - 1, jump-end);
  596. &.state2 {
  597. left: calc(-100% * (@frame-num-3 - 1));
  598. }
  599. }
  600. }
  601. >img.btn-track{
  602. position: absolute;
  603. width: 598px;
  604. height: 598px;
  605. left: -150px;
  606. bottom: -101px;
  607. }
  608. >button.btn-on-track{
  609. position: absolute;
  610. width: 78px;
  611. height: 78px;
  612. background-size: cover;
  613. background-repeat: no-repeat;
  614. background-position: center center;
  615. text-align: left;
  616. z-index: 3;
  617. >span{
  618. margin-left: 120px;
  619. display: none;
  620. font-size: 23px;
  621. font-family: Source Han Serif SC, Source Han Serif SC;
  622. font-weight: 600;
  623. color: #FFF1BE;
  624. line-height: 27px;
  625. letter-spacing: 5px;
  626. }
  627. &:hover{
  628. width: 397px;
  629. height: 91px;
  630. transform: translate(-13px, -5px);
  631. >span{
  632. display: initial;
  633. }
  634. }
  635. }
  636. >button.one{
  637. left: 210px;
  638. top: -42px;
  639. background-image: v-bind(btnOnTrack1ImgUrl);
  640. &:hover{
  641. background-image: v-bind(btnOnTrack1ActiveImgUrl);
  642. }
  643. }
  644. >button.two{
  645. left: 336px;
  646. top: 62px;
  647. background-image: v-bind(btnOnTrack2ImgUrl);
  648. &:hover{
  649. background-image: v-bind(btnOnTrack2ActiveImgUrl);
  650. }
  651. }
  652. >button.three{
  653. left: 385px;
  654. top: 205px;
  655. background-image: v-bind(btnOnTrack3ImgUrl);
  656. &:hover{
  657. background-image: v-bind(btnOnTrack3ActiveImgUrl);
  658. }
  659. }
  660. >button.four{
  661. left: 352px;
  662. top: 353px;
  663. background-image: v-bind(btnOnTrack4ImgUrl);
  664. &:hover{
  665. background-image: v-bind(btnOnTrack4ActiveImgUrl);
  666. }
  667. }
  668. }
  669. >div.camera-list{
  670. position: absolute;
  671. bottom: 0;
  672. right: 0;
  673. width: calc(1346 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  674. height: calc(161 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  675. background-image: v-bind(cameraListBgUrl);
  676. background-size: cover;
  677. background-repeat: no-repeat;
  678. background-position: center center;
  679. display: flex;
  680. justify-content: flex-end;
  681. align-items: center;
  682. padding-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  683. padding-right: calc(204 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  684. >button.camera-entry{
  685. width: calc(198 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  686. height: calc(41 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  687. font-size: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  688. font-family: Source Han Serif SC, Source Han Serif SC;
  689. font-weight: 600;
  690. color: #FFED87;
  691. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  692. letter-spacing: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  693. position: relative;
  694. z-index: 0;
  695. >img.bg-normal{
  696. display: initial;
  697. position: absolute;
  698. left: 50%;
  699. top: 50%;
  700. transform: translate(-50%, -50%);
  701. width: calc(198/ v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  702. height: calc(55 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  703. z-index: -1;
  704. }
  705. >img.bg-active{
  706. display: none;
  707. position: absolute;
  708. left: 50%;
  709. top: 0%;
  710. transform: translate(-50%, -50%);
  711. width: calc(230 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  712. height: auto;
  713. z-index: -1;
  714. }
  715. }
  716. >button.camera-entry.active{
  717. font-size: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  718. font-family: Source Han Serif SC, Source Han Serif SC;
  719. font-weight: 600;
  720. color: #794A00;
  721. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  722. letter-spacing: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  723. >img.bg-normal{
  724. display: none;
  725. }
  726. >img.bg-active{
  727. display: initial;
  728. }
  729. }
  730. >button.next-scene{
  731. position: absolute;
  732. top: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  733. right: calc(45 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  734. width: calc(70 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  735. height: calc(100 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  736. }
  737. }
  738. >.camera-content{
  739. z-index: 10;
  740. }
  741. >video.sceneChangeEffectVideo{
  742. position: absolute;
  743. left: 0;
  744. top: 0;
  745. width: 100%;
  746. height: 100%;
  747. background-color: black;
  748. z-index: 11;
  749. }
  750. .cloud-top{
  751. position: absolute;
  752. width: 100%;
  753. top: 0;
  754. left: 0;
  755. z-index: 12;
  756. }
  757. .cloud-top-enter-active {
  758. transition: all 1.5s;
  759. }
  760. .cloud-top-leave-active {
  761. transition: all 1.5s;
  762. pointer-events: none;
  763. }
  764. .cloud-top-enter-from {
  765. opacity: 0;
  766. translate: 0 -100%;
  767. }
  768. .cloud-top-leave-to {
  769. opacity: 0;
  770. top: -50%;
  771. translate: 0 -100%;
  772. }
  773. .cloud-left-bottom{
  774. position: absolute;
  775. left: 0;
  776. bottom: 0;
  777. height: 70%;
  778. z-index: 12;
  779. }
  780. .cloud-left-bottom-enter-active {
  781. transition: all 1.5s;
  782. }
  783. .cloud-left-bottom-leave-active {
  784. transition: all 1.5s;
  785. pointer-events: none;
  786. }
  787. .cloud-left-bottom-enter-from {
  788. opacity: 0;
  789. translate: -100% 100%;
  790. }
  791. .cloud-left-bottom-leave-to {
  792. opacity: 0;
  793. pointer-events: none;
  794. translate: -100% 100%;
  795. }
  796. .cloud-right-bottom{
  797. position: absolute;
  798. right: 0;
  799. bottom: 0;
  800. height: 95%;
  801. z-index: 12;
  802. }
  803. .cloud-right-bottom-enter-active {
  804. transition: all 1.5s;
  805. }
  806. .cloud-right-bottom-leave-active {
  807. transition: all 1.5s;
  808. pointer-events: none;
  809. }
  810. .cloud-right-bottom-enter-from {
  811. opacity: 0;
  812. translate: 100% 100%;
  813. }
  814. .cloud-right-bottom-leave-to {
  815. opacity: 0;
  816. pointer-events: none;
  817. translate: 100% 100%;
  818. }
  819. }
  820. @keyframes character-default-animation {
  821. 0% {
  822. translate: 0 0;
  823. }
  824. 100% {
  825. translate: -100% 0;
  826. }
  827. }
  828. </style>