PanoView.vue 25 KB

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