PanoView.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  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="@/assets/images/people-btn-track.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 === activeCameraIdx
  110. }"
  111. @mouseenter="activeCameraIdx = idx"
  112. @mouseleave="activeCameraIdx = sceneIdx"
  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="@/assets/images/camera-list-item-bg.png"
  125. alt=""
  126. draggable="false"
  127. >
  128. <img
  129. class="bg-active"
  130. src="@/assets/images/camera-list-item-bg-active.png"
  131. alt=""
  132. draggable="false"
  133. >
  134. </button>
  135. <button class="next-camera" />
  136. </div>
  137. <CameraContent1
  138. v-if="showingContentIdx === 1"
  139. class="camera-content"
  140. @close="showingContentIdx = 0"
  141. />
  142. <CameraContent2
  143. v-if="showingContentIdx === 2"
  144. class="camera-content"
  145. @close="showingContentIdx = 0"
  146. />
  147. <CameraContent3
  148. v-if="showingContentIdx === 3"
  149. class="camera-content"
  150. @close="showingContentIdx = 0"
  151. />
  152. </div>
  153. </template>
  154. <script setup>
  155. import { ref, computed, watch, onMounted, nextTick } from "vue"
  156. import { useRoute, useRouter, onBeforeRouteUpdate } from "vue-router"
  157. import { useStore } from "vuex"
  158. import * as krfn from "@/libs/pano-core/index.js"
  159. import CameraDesc from '@/components/CameraDesc.vue'
  160. import CharacterDesc from '@/components/CharacterDesc.vue'
  161. import { defineAsyncComponent } from 'vue'
  162. const CameraContent1 = defineAsyncComponent(() =>
  163. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-1.vue`)
  164. )
  165. const CameraContent2 = defineAsyncComponent(() =>
  166. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-2.vue`)
  167. )
  168. const CameraContent3 = defineAsyncComponent(() =>
  169. import(`@/components/CameraContent-${Number(route.query.sceneIdx) + 1}-${Number(route.query.cameraIdx) + 1}-3.vue`)
  170. )
  171. const {
  172. windowSizeInCssForRef,
  173. windowSizeWhenDesignForRef,
  174. } = useSizeAdapt()
  175. const route = useRoute()
  176. const router = useRouter()
  177. const store = useStore()
  178. const sceneIdx = computed(() => {
  179. return Number(route.query.sceneIdx)
  180. })
  181. const cameraIdx = computed(() => {
  182. return Number(route.query.cameraIdx)
  183. })
  184. const isCharacterSpecialMoving = ref(0)
  185. const animationType = ref(1)
  186. const isShowCameraDesc = ref(false)
  187. const isShowCharacterDesc = ref(false)
  188. const showingContentIdx = ref(0)
  189. function onClickCharacter() {
  190. isShowCameraDesc.value = true
  191. if (!isCharacterSpecialMoving.value) {
  192. animationType.value = Math.floor(Math.random() * 2) + 2
  193. let duration = 0
  194. switch (animationType.value) {
  195. case 2:
  196. duration = 2000
  197. break
  198. case 3:
  199. duration = 1500
  200. break
  201. default:
  202. break
  203. }
  204. setTimeout(() => {
  205. isCharacterSpecialMoving.value = 1
  206. setTimeout(() => {
  207. isCharacterSpecialMoving.value = 0
  208. animationType.value = 1
  209. }, duration)
  210. }, 200)
  211. }
  212. }
  213. const sceneList = ref([
  214. {
  215. sceneName: '大汗之城',
  216. cameraList: [
  217. {
  218. name: '雄伟帝都',
  219. // panoCode: 'WK1730511898643845120',
  220. panoCode: 'WK1730428603763576832',
  221. contentPageBtnNameList: [
  222. '整体设计与规划',
  223. '营都人员与机构',
  224. '史料中的元大都',
  225. ],
  226. },
  227. {
  228. name: '大都宫阙',
  229. panoCode: 'WK1730165377477955584',
  230. contentPageBtnNameList: [
  231. '皇城与宫城',
  232. '皇城内的建筑布局',
  233. '忽必烈召见赵孟頫',
  234. ],
  235. },
  236. {
  237. name: '大都览胜',
  238. panoCode: 'WK1730164600466362368',
  239. contentPageBtnNameList: [
  240. '大都城内的寺庙建筑',
  241. '大都城内的官署机构',
  242. '重要建筑构件',
  243. ],
  244. },
  245. ]
  246. },
  247. {
  248. sceneName: '河润大都',
  249. cameraList: [
  250. {
  251. name: '通惠河畅',
  252. contentPageBtnNameList: [
  253. '大运河的历史演变',
  254. '元大都用水水系',
  255. '水利专家及对通惠河段的治理',
  256. ],
  257. },
  258. {
  259. name: '舳舻蔽水',
  260. contentPageBtnNameList: [
  261. '菏泽沉船',
  262. '磁县漕船',
  263. '聊城古船',
  264. ],
  265. },
  266. {
  267. name: '繁华富庶',
  268. contentPageBtnNameList: [
  269. '造福百姓',
  270. '元代瓷器的发展',
  271. ' 商品贸易中的货币',
  272. ],
  273. },
  274. ]
  275. },
  276. {
  277. sceneName: '大都风华',
  278. cameraList: [
  279. {
  280. name: '文人雅集',
  281. contentPageBtnNameList: [
  282. '元代文化艺术的发展',
  283. '上流社会的雅集盛会',
  284. '百工精巧',
  285. ],
  286. },
  287. {
  288. name: '曲苑杂剧',
  289. contentPageBtnNameList: [
  290. '元曲的文化成就',
  291. '著名元曲作家与作品',
  292. '表演元曲的著名演员',
  293. ],
  294. },
  295. ]
  296. },
  297. ])
  298. const currentCameraList = computed(() => {
  299. return sceneList.value[sceneIdx.value].cameraList
  300. })
  301. const activeCameraIdx = ref(sceneIdx.value)
  302. const btnOnTrack1ImgUrl = computed(() => {
  303. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-1.png`) + ')'
  304. })
  305. const btnOnTrack1ActiveImgUrl = computed(() => {
  306. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-1-active.png`) + ')'
  307. })
  308. const btnOnTrack2ImgUrl = computed(() => {
  309. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-2.png`) + ')'
  310. })
  311. const btnOnTrack2ActiveImgUrl = computed(() => {
  312. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-2-active.png`) + ')'
  313. })
  314. const btnOnTrack3ImgUrl = computed(() => {
  315. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-3.png`) + ')'
  316. })
  317. const btnOnTrack3ActiveImgUrl = computed(() => {
  318. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-3-active.png`) + ')'
  319. })
  320. const btnOnTrack4ImgUrl = computed(() => {
  321. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-4.png`) + ')'
  322. })
  323. const btnOnTrack4ActiveImgUrl = computed(() => {
  324. return `url(${process.env.VUE_APP_CLI_MODE === 'dev' ? '' : '../'}` + require(`@/assets/images/camera-btn-${sceneIdx.value + 1}-${cameraIdx.value + 1}-4-active.png`) + ')'
  325. })
  326. const btnOnTrack1Name = computed(() => {
  327. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[0]
  328. })
  329. const btnOnTrack2Name = computed(() => {
  330. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[1]
  331. })
  332. const btnOnTrack3Name = computed(() => {
  333. return currentCameraList.value[cameraIdx.value].contentPageBtnNameList[2]
  334. })
  335. /**
  336. * 全景图
  337. */
  338. let __krfn = krfn.default
  339. window.__krfn = __krfn
  340. let scene = null
  341. function fixPanoData(panoData) {
  342. // 丢弃没有包含场景的二级分组
  343. let tmp = []
  344. panoData.scenes.forEach((item) => {
  345. panoData.catalogs.forEach((sub) => {
  346. if (item.category == sub.id) {
  347. if (tmp.indexOf(sub) < 0) {
  348. tmp.push(sub)
  349. }
  350. }
  351. })
  352. })
  353. tmp = utils.unique(tmp)
  354. panoData.catalogs = tmp
  355. // 丢弃没有包含二级分组的一级分组
  356. let rootmp = []
  357. tmp.forEach((item) => {
  358. panoData.catalogRoot.forEach((sub) => {
  359. sub.children = utils.unique(sub.children)
  360. if (sub.children.indexOf(item.id) > -1) {
  361. rootmp.push(sub)
  362. }
  363. })
  364. })
  365. rootmp = utils.unique(rootmp)
  366. // 一级分组按名称排序
  367. let sortArr = panoData.catalogRoot.map((item) => item.name)
  368. rootmp.sort((a, b) => {
  369. return sortArr.indexOf(a.name) - sortArr.indexOf(b.name)
  370. })
  371. // 各个一级分组的children去重,只留下有实际的二级分组相对应的那些children item。
  372. panoData.catalogRoot = rootmp.map((item) => {
  373. let temp = []
  374. item.children = utils.unique(item.children)
  375. item.children.forEach((sub) => {
  376. tmp.forEach((jj) => {
  377. if (jj.id == sub) {
  378. temp.push(sub)
  379. }
  380. })
  381. })
  382. return {
  383. ...item,
  384. children: temp,
  385. }
  386. })
  387. // 多余
  388. panoData.catalogs = tmp
  389. // 如果没有一级分组(一定也就没有二级分组)就创建一级分组和二级分组 有必要吗?
  390. let cid = "c_" + utils.randomWord(true, 8, 8)
  391. if (panoData.catalogRoot.length <= 0) {
  392. panoData.catalogRoot.push({
  393. id: "r_" + utils.randomWord(true, 8, 8),
  394. name: "全部场景",
  395. children: [cid],
  396. })
  397. }
  398. if (panoData.catalogs.length <= 0) {
  399. panoData.catalogs.push({
  400. id: cid,
  401. name: "默认二级分组",
  402. })
  403. }
  404. // 如果有初始场景,改为引用场景列表中对应的那个场景的js对象
  405. if (panoData.firstScene) {
  406. panoData.firstScene = panoData.scenes.find(
  407. (item) => item.sceneCode == panoData.firstScene.sceneCode
  408. )
  409. }
  410. }
  411. function loadScene(sceneIdx, cameraIdx) {
  412. scene = store.getters.catalogTopology[sceneIdx].children[0].children[cameraIdx]
  413. $("#pano").empty()
  414. window.vrInitFn = () => {
  415. // eslint-disable-next-line no-undef
  416. // $smallWaiting.hide()
  417. var krpano = document.getElementById("krpanoSWFObject")
  418. __krfn.utils.initHotspot(krpano, scene.someData, false)
  419. }
  420. window.vrViewFn = () => {
  421. try {
  422. let tmp = scene.initVisual || {}
  423. var krpano = document.getElementById("krpanoSWFObject")
  424. krpano.set("view.vlookat", tmp.vlookat || 0)
  425. krpano.set("view.hlookat", tmp.hlookat || 0)
  426. krpano.set("autorotate.enabled", Boolean(store.state.panoData.isAuto))
  427. } catch (error) {
  428. console.log(error)
  429. }
  430. }
  431. let settings = {
  432. "events[skin_events].onxmlcomplete": "js(window.vrViewFn());",
  433. "events[skin_events].onloadcomplete": "js(window.vrInitFn());",
  434. }
  435. // eslint-disable-next-line no-undef
  436. removepano("#pano")
  437. // eslint-disable-next-line no-undef
  438. embedpano({
  439. xml: `https://4dkk.4dage.com/720yun_fd_manage/${scene.sceneCode}/vtour/tour.xml`,
  440. swf: `${process.env.BASE_URL}static/template/tour.swf`, // 文件名tour.swf没看出来有啥作用,不写也行。但它的路径决定了 %SWFPATH% 的值。
  441. target: "pano",
  442. html5: "auto",
  443. mobilescale: 1,
  444. vars: settings,
  445. passQueryParameters: true,
  446. })
  447. }
  448. onMounted(() => {
  449. api.fetchPanoData('WK1730428603763576832').then((res) => {
  450. fixPanoData(res)
  451. store.commit('setPanoData', res)
  452. console.log('catalogTopology', store.getters.catalogTopology)
  453. loadScene(Number(sceneIdx.value), Number(cameraIdx.value))
  454. })
  455. })
  456. onBeforeRouteUpdate((to, from) => {
  457. console.log('to: ', to)
  458. if (to.name === route.name) {
  459. loadScene(Number(to.query.sceneIdx), Number(to.query.cameraIdx))
  460. }
  461. })
  462. </script>
  463. <style lang="less" scoped>
  464. *{
  465. user-select: none;
  466. }
  467. .pano-view{
  468. position: relative;
  469. height: 100%;
  470. >#pano{
  471. position: absolute;
  472. left: 0;
  473. top: 0;
  474. width: 100%;
  475. height: 100%;
  476. }
  477. >button.return-home{
  478. position: absolute;
  479. width: 77px;
  480. height: 77px;
  481. top: 43px;
  482. right: 51px;
  483. background-image: url(@/assets/images/btn-return-home.png);
  484. background-size: cover;
  485. background-repeat: no-repeat;
  486. background-position: center center;
  487. &:hover{
  488. background-image: url(@/assets/images/btn-return-home-active.png);
  489. }
  490. }
  491. >.camera-desc{
  492. z-index: 5;
  493. }
  494. >.character-desc{
  495. z-index: 5;
  496. }
  497. >.character-wrap{
  498. position: absolute;
  499. left: 40px;
  500. bottom: 0;
  501. width: 300px;
  502. height: 452px;
  503. >button.name{
  504. position: absolute;
  505. top: 50px;
  506. left: 0;
  507. transform: translateX(-50%);
  508. width: 36px;
  509. height: 178px;
  510. z-index: 3;
  511. font-size: 23px;
  512. font-family: Source Han Serif SC, Source Han Serif SC;
  513. font-weight: 400;
  514. color: #43310E;
  515. line-height: 27px;
  516. letter-spacing: 7px;
  517. writing-mode: vertical-lr;
  518. background-image: url(@/assets/images/people-name-bg.png);
  519. background-size: contain;
  520. background-repeat: no-repeat;
  521. background-position: center center;
  522. >span{
  523. position: absolute;
  524. left: 45%;
  525. top: 50%;
  526. transform: translate(-50%, -50%);
  527. }
  528. }
  529. @frame-width: 256px;
  530. @frame-height: 512px;
  531. @duration-1: 3s;
  532. @frame-num-1: 72;
  533. @duration-2: 2s;
  534. @frame-num-2: 48;
  535. @duration-3: 1.5s;
  536. @frame-num-3: 36;
  537. >.character-frames-wrapper {
  538. position: absolute;
  539. left: 0;
  540. top: -60px;
  541. height: @frame-height;
  542. width: @frame-width;
  543. overflow: hidden;
  544. z-index: 1;
  545. cursor: pointer;
  546. >.default-frames{
  547. position: absolute;
  548. left: 0;
  549. height: 100%;
  550. animation-name: character-default-animation;
  551. animation-timing-function: steps(73, end);
  552. animation-duration: 3s;
  553. animation-iteration-count: infinite;
  554. }
  555. >.frames {
  556. position: absolute;
  557. height: 100%;
  558. transition-property: none;
  559. &.animating{
  560. transition-property: left;
  561. }
  562. &.state1 {
  563. left: 0;
  564. }
  565. }
  566. >.frames-2{
  567. transition-duration: @duration-2;
  568. transition-timing-function: steps(@frame-num-2 - 1, jump-end);
  569. &.state2 {
  570. left: calc(-100% * (@frame-num-2 - 1));
  571. }
  572. }
  573. >.frames-3{
  574. transition-duration: @duration-3;
  575. transition-timing-function: steps(@frame-num-3 - 1, jump-end);
  576. &.state2 {
  577. left: calc(-100% * (@frame-num-3 - 1));
  578. }
  579. }
  580. }
  581. >img.btn-track{
  582. position: absolute;
  583. width: 598px;
  584. height: 598px;
  585. left: -150px;
  586. bottom: -101px;
  587. }
  588. >button.btn-on-track{
  589. position: absolute;
  590. width: 78px;
  591. height: 78px;
  592. background-size: cover;
  593. background-repeat: no-repeat;
  594. background-position: center center;
  595. text-align: left;
  596. z-index: 3;
  597. >span{
  598. margin-left: 120px;
  599. display: none;
  600. font-size: 23px;
  601. font-family: Source Han Serif SC, Source Han Serif SC;
  602. font-weight: 600;
  603. color: #FFF1BE;
  604. line-height: 27px;
  605. letter-spacing: 5px;
  606. }
  607. &:hover{
  608. width: 397px;
  609. height: 91px;
  610. transform: translate(-13px, -5px);
  611. >span{
  612. display: initial;
  613. }
  614. }
  615. }
  616. >button.one{
  617. left: 210px;
  618. top: -42px;
  619. background-image: v-bind(btnOnTrack1ImgUrl);
  620. &:hover{
  621. background-image: v-bind(btnOnTrack1ActiveImgUrl);
  622. }
  623. }
  624. >button.two{
  625. left: 336px;
  626. top: 62px;
  627. background-image: v-bind(btnOnTrack2ImgUrl);
  628. &:hover{
  629. background-image: v-bind(btnOnTrack2ActiveImgUrl);
  630. }
  631. }
  632. >button.three{
  633. left: 385px;
  634. top: 205px;
  635. background-image: v-bind(btnOnTrack3ImgUrl);
  636. &:hover{
  637. background-image: v-bind(btnOnTrack3ActiveImgUrl);
  638. }
  639. }
  640. >button.four{
  641. left: 352px;
  642. top: 353px;
  643. background-image: v-bind(btnOnTrack4ImgUrl);
  644. &:hover{
  645. background-image: v-bind(btnOnTrack4ActiveImgUrl);
  646. }
  647. }
  648. }
  649. >div.camera-list{
  650. position: absolute;
  651. bottom: 0;
  652. right: 0;
  653. width: calc(1346 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  654. height: calc(161 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  655. background-image: url(@/assets/images/camera-list-bg.png);
  656. background-size: cover;
  657. background-repeat: no-repeat;
  658. background-position: center center;
  659. display: flex;
  660. justify-content: flex-end;
  661. align-items: center;
  662. padding-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  663. padding-right: calc(204 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  664. >button.camera-entry{
  665. width: calc(198 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  666. height: calc(41 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  667. font-size: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  668. font-family: Source Han Serif SC, Source Han Serif SC;
  669. font-weight: 600;
  670. color: #FFED87;
  671. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  672. letter-spacing: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  673. position: relative;
  674. z-index: 0;
  675. >img.bg-normal{
  676. display: initial;
  677. position: absolute;
  678. left: 50%;
  679. top: 50%;
  680. transform: translate(-50%, -50%);
  681. width: calc(198/ v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  682. height: calc(55 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  683. z-index: -1;
  684. }
  685. >img.bg-active{
  686. display: none;
  687. position: absolute;
  688. left: 50%;
  689. top: 0%;
  690. transform: translate(-50%, -50%);
  691. width: calc(230 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  692. height: auto;
  693. z-index: -1;
  694. }
  695. }
  696. >button.camera-entry.active{
  697. font-size: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  698. font-family: Source Han Serif SC, Source Han Serif SC;
  699. font-weight: 600;
  700. color: #794A00;
  701. line-height: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  702. letter-spacing: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  703. >img.bg-normal{
  704. display: none;
  705. }
  706. >img.bg-active{
  707. display: initial;
  708. }
  709. }
  710. >button.next-camera{
  711. position: absolute;
  712. top: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  713. right: calc(45 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  714. width: calc(70 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  715. height: calc(100 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  716. }
  717. }
  718. >.camera-content{
  719. z-index: 10;
  720. }
  721. }
  722. @keyframes character-default-animation {
  723. 0% {
  724. translate: 0 0;
  725. }
  726. 100% {
  727. translate: -100% 0;
  728. }
  729. }
  730. </style>