|
@@ -0,0 +1,642 @@
|
|
|
+<template>
|
|
|
+ <div class="controls-left-buttons">
|
|
|
+ <div class="play-control" v-if="tours.length > 0" :class="{ disabled: flying && !isPlay }">
|
|
|
+ <div class="play-btn tour-btn" @click="playTour">
|
|
|
+ <div class="animation-icon" :class="{ action: isPlay }" :style="`background-image: url(${resource.getStaticURL('static/images/walk_animation.png')});`">
|
|
|
+ <p class="tip">{{ isPlay ? $t('common.pauseTour') : $t('common.playTour') }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="tour-btn bor">
|
|
|
+ <ui-icon type="pull-down" @click="openTours" :class="{ active: showTours }"></ui-icon>
|
|
|
+ </div>
|
|
|
+ <!-- <teleport :to="editorMain"> -->
|
|
|
+ <div class="tour-list" :class="{ ban: flying || isSelect }" :style="`height:${showTours ? '120px' : '0px'};`">
|
|
|
+ <div class="part-content" ref="tourScroll">
|
|
|
+ <!-- 多个片段 -->
|
|
|
+ <div class="part-list" v-if="tours.length > 1">
|
|
|
+ <div
|
|
|
+ @click="changeFrame(1, index)"
|
|
|
+ class="part-item"
|
|
|
+ :name="index"
|
|
|
+ v-for="(i, index) in tours"
|
|
|
+ :style="`background-image:url(${i.frameId && i.list[i.frameId] ? common.changeUrl(i.list[i.frameId].enter.cover) : common.changeUrl(i.list[0].enter.cover)});`"
|
|
|
+ >
|
|
|
+ <div class="part-title">{{ i.name }}</div>
|
|
|
+ <div v-if="partId == index && progressNum > 0" class="precent" :style="`width:${progressNum}%;`"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 只有一个片段 -->
|
|
|
+ <div class="part-list frame-list" v-else>
|
|
|
+ <div @click="changeFrame(2, index)" class="part-item" v-for="(i, index) in tours[0].list" :name="index" :style="`background-image:url(${common.changeUrl(i.enter.cover)});`">
|
|
|
+ <div class="part-title"></div>
|
|
|
+ <div v-if="frameId == index && progressNum > 0" class="precent" :style="`width:${progressNum}%;`"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- </teleport> -->
|
|
|
+ </div>
|
|
|
+ <div class="buttons mode" :class="{ disabled: isPlay || flying }">
|
|
|
+ <div v-if="controls.showPanorama" :class="{ active: viewmode == 'panorama' }" @click="onModeChange('panorama')">
|
|
|
+ <ui-icon :tip="$t('mode.panorama')" tipV="top" :type="viewmode == 'panorama' ? 'show_roaming_s' : 'show_roaming_n'"></ui-icon>
|
|
|
+ </div>
|
|
|
+ <div v-if="controls.showFloorplan" :class="{ active: viewmode == 'floorplan' }" @click="onModeChange('floorplan')">
|
|
|
+ <ui-icon :tip="$t('mode.floorplan')" tipV="top" :type="viewmode == 'floorplan' ? 'show_plane_s' : 'show_plane_n'"></ui-icon>
|
|
|
+ </div>
|
|
|
+ <div v-if="controls.showDollhouse" :class="{ active: viewmode == 'dollhouse' }" @click="onModeChange('dollhouse')">
|
|
|
+ <ui-icon :tip="$t('mode.dollhouse')" tipV="top" :type="viewmode == 'dollhouse' ? 'show_3d_s' : 'show_3d_n'"></ui-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 导览字幕 -->
|
|
|
+ <!-- <teleport to=".kankan-app" > -->
|
|
|
+ <div class="tours-captions" :class="{ active: showTours }" v-if="tours.length > 0 && isPlay">
|
|
|
+ <div class="captions-title" v-if="tours[partId] && tours[partId].title">{{ tours[partId].title || '' }}</div>
|
|
|
+ <div class="captions-desc" v-if="tours[partId] && tours[partId].description">{{ tours[partId].description || '' }}</div>
|
|
|
+ </div>
|
|
|
+ <!-- </teleport> -->
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { computed, defineProps, onMounted, ref, nextTick, watch } from 'vue'
|
|
|
+import { Scrollbar, Dialog } from '@kankan/components'
|
|
|
+import { useApp, getApp } from '@/app'
|
|
|
+import { useStore } from 'vuex'
|
|
|
+import browser from '@/utils/browser'
|
|
|
+import common from '@/utils/common'
|
|
|
+import resource from '@/utils/resource'
|
|
|
+import { useMusicPlayer } from '@/utils/sound'
|
|
|
+import { Track, startTrack, endTrack } from '@/utils/track.js'
|
|
|
+// import test from './test.vue'
|
|
|
+const musicPlayer = useMusicPlayer()
|
|
|
+const props = defineProps({
|
|
|
+ isEdit: Boolean,
|
|
|
+})
|
|
|
+let timer = null
|
|
|
+const isSelect = ref(false)
|
|
|
+const store = useStore()
|
|
|
+const tourScroll = ref(null)
|
|
|
+const viewmode = computed(() => store.getters.mode)
|
|
|
+const flying = computed(() => store.getters['flying'])
|
|
|
+const controls = computed(() => store.getters['scene/metadata'].controls || {})
|
|
|
+const showTours = computed(() => store.getters['tour/showTours'])
|
|
|
+const sceneUI = computed(() => store.getters.sceneUI)
|
|
|
+const partId = computed(() => {
|
|
|
+ let id = store.getters['tour/partId']
|
|
|
+ if (isPlay.value) {
|
|
|
+ slideScroll()
|
|
|
+ }
|
|
|
+ return id
|
|
|
+})
|
|
|
+
|
|
|
+const frameId = computed(() => {
|
|
|
+ let id = store.getters['tour/frameId']
|
|
|
+ if (isPlay.value) {
|
|
|
+ slideScroll()
|
|
|
+ }
|
|
|
+ return id
|
|
|
+})
|
|
|
+const progressNum = ref(0)
|
|
|
+const isPlay = computed(() => {
|
|
|
+ let status = store.getters['tour/isPlay']
|
|
|
+ let map = document.querySelector('.kankan-app div[xui_min_map]')
|
|
|
+ if (map) {
|
|
|
+ if (status) {
|
|
|
+ map.classList.add('disabled')
|
|
|
+ } else {
|
|
|
+ map.classList.remove('disabled')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return status
|
|
|
+})
|
|
|
+const isInit = ref(false)
|
|
|
+const tours = computed(() => {
|
|
|
+ let tours = store.getters['tour/tours']
|
|
|
+ if (tours.length > 0) {
|
|
|
+ if (tourScroll.value && !isInit.value) {
|
|
|
+ isInit.value = true
|
|
|
+ new Scrollbar(tourScroll.value, { onlyHorizontal: true })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return tours
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => sceneUI.value,
|
|
|
+ (val, old) => {
|
|
|
+ if (showTours.value) {
|
|
|
+ if (val) {
|
|
|
+ store.commit('setControlsBottom', '120px')
|
|
|
+ } else {
|
|
|
+ store.commit('setControlsBottom', '0')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+const onModeChange = name => {
|
|
|
+ store.commit('setMode', name)
|
|
|
+ Track('view-button', {
|
|
|
+ eventType: 'click',
|
|
|
+ click: name,
|
|
|
+ })
|
|
|
+}
|
|
|
+const playTour = async () => {
|
|
|
+ let player = await getApp().TourManager.player
|
|
|
+ if (isPlay.value) {
|
|
|
+ store.commit('tour/setData', { isPlay: true })
|
|
|
+ player.pause()
|
|
|
+ } else {
|
|
|
+ store.commit('tour/setData', { isPlay: true })
|
|
|
+ player.play(partId.value, frameId.value)
|
|
|
+ }
|
|
|
+ store.commit('tag/setData', { isFixed: false, isClick: false, flyClose: false })
|
|
|
+ store.commit('tag/closeTag')
|
|
|
+
|
|
|
+ //自动打开导览
|
|
|
+ if (isPlay.value) {
|
|
|
+ store.commit('tour/setData', { showTours: true })
|
|
|
+ let bot = '0px'
|
|
|
+ if (showTours.value) {
|
|
|
+ bot = '120px'
|
|
|
+ } else {
|
|
|
+ bot = '0px'
|
|
|
+ }
|
|
|
+ store.commit('setControlsBottom', bot)
|
|
|
+ nextTick(() => {
|
|
|
+ if (isPlay.value) {
|
|
|
+ slideScroll()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const hanlderTourPartPlay = time => {
|
|
|
+ if (!timer) {
|
|
|
+ timer = KanKan.Animate.transitions.start(progress => {
|
|
|
+ progressNum.value = progress * 100
|
|
|
+ }, time)
|
|
|
+ }
|
|
|
+}
|
|
|
+const cancelTimer = () => {
|
|
|
+ if (timer) {
|
|
|
+ KanKan.Animate.transitions.cancel(timer)
|
|
|
+ timer = null
|
|
|
+ }
|
|
|
+}
|
|
|
+const slideScroll = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ let t = setTimeout(() => {
|
|
|
+ clearTimeout(t)
|
|
|
+ let id = tours.value.length > 1 ? partId.value : frameId.value
|
|
|
+ let item = document.querySelector(`.part-item[name="${id}"]`)
|
|
|
+ item.scrollIntoView({ block: 'nearest', behavior: 'smooth', inline: 'center' })
|
|
|
+ }, 100)
|
|
|
+ })
|
|
|
+}
|
|
|
+let tour_finish = false
|
|
|
+const hanlderTour = async () => {
|
|
|
+ let player = await getApp().TourManager.player
|
|
|
+ player.on('play', data => {
|
|
|
+ tour_finish = false
|
|
|
+ musicPlayer.pause(true)
|
|
|
+ Track('view-tour', {
|
|
|
+ eventType: 'click',
|
|
|
+ click: 'play',
|
|
|
+ })
|
|
|
+ })
|
|
|
+ player.on('pause', tours => {
|
|
|
+ console.log('pause')
|
|
|
+ musicPlayer.resume()
|
|
|
+ currProgress = 0
|
|
|
+ currFrameProgress = 0
|
|
|
+ progressNum.value = 0
|
|
|
+ cancelTimer()
|
|
|
+ store.commit('tour/setData', { isPlay: false })
|
|
|
+ })
|
|
|
+ player.on('end', () => {
|
|
|
+ tour_finish = true
|
|
|
+ musicPlayer.resume()
|
|
|
+ currProgress = 0
|
|
|
+ currFrameProgress = 0
|
|
|
+ progressNum.value = 100
|
|
|
+ slideScroll()
|
|
|
+ store.commit('tour/setData', { isPlay: false })
|
|
|
+ cancelTimer()
|
|
|
+
|
|
|
+ // 循环播放导览
|
|
|
+ if (browser.hasURLParam('tour_loop')) {
|
|
|
+ setTimeout(() => {
|
|
|
+ playTour()
|
|
|
+ }, 1000)
|
|
|
+ }
|
|
|
+ //当最后一个有热点时候,需要展开
|
|
|
+ if (tours.value[partId.value].list[frameId.value].tagId) {
|
|
|
+ getApp().TagManager.open(tours.value[partId.value].list[frameId.value].tagId)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ let currPartId = null
|
|
|
+ let currFrameId = null
|
|
|
+ let currProgress = 0
|
|
|
+ let FrameLength = 0
|
|
|
+ let currFrameProgress = 0
|
|
|
+
|
|
|
+ player.on('progress', data => {
|
|
|
+ if (tour_finish) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currPartId != data.partId || currFrameId != data.frameId) {
|
|
|
+ if (!tours.value[data.partId].list[data.frameId].tagId) {
|
|
|
+ store.commit('tag/closeTag')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (tours.value.length == 1) {
|
|
|
+ progressNum.value = data.progress * 100
|
|
|
+ currPartId = data.partId
|
|
|
+ currFrameId = data.frameId
|
|
|
+ } else {
|
|
|
+ // let time = getPartTime(data.partId)
|
|
|
+
|
|
|
+ // hanlderTourPartPlay(time)
|
|
|
+
|
|
|
+ if (currPartId != data.partId) {
|
|
|
+ currProgress = 0
|
|
|
+ currFrameProgress = 0
|
|
|
+ progressNum.value = 0
|
|
|
+ currPartId = data.partId
|
|
|
+ FrameLength = tours.value[data.partId].list.length
|
|
|
+ } else {
|
|
|
+ FrameLength = tours.value[data.partId].list.length
|
|
|
+
|
|
|
+ if (currFrameId != data.frameId) {
|
|
|
+ currFrameId = data.frameId
|
|
|
+ currFrameProgress = currProgress
|
|
|
+ } else {
|
|
|
+ currProgress = (data.progress / FrameLength) * 100 + currFrameProgress
|
|
|
+ }
|
|
|
+ if (currProgress >= 100) {
|
|
|
+ currProgress = 100
|
|
|
+ }
|
|
|
+
|
|
|
+ progressNum.value = currProgress
|
|
|
+ }
|
|
|
+ }
|
|
|
+ store.commit('tour/setData', { partId: data.partId, frameId: data.frameId })
|
|
|
+ })
|
|
|
+
|
|
|
+ // 导览自动播放
|
|
|
+ getApp().TourManager.on('loaded', () => {
|
|
|
+ if (browser.hasURLParam('autoplay')) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (tours.value.length) {
|
|
|
+ let hasMusic = false
|
|
|
+ for (let i = 0; i < tours.value.length; i++) {
|
|
|
+ if (tours.value[i].music) {
|
|
|
+ hasMusic = true
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!hasMusic) {
|
|
|
+ //当所有片段没有背景音乐时,才能自动播放
|
|
|
+ playTour()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 500)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+const getPartTime = partId => {
|
|
|
+ cancelTimer()
|
|
|
+ let time = 0
|
|
|
+ for (let i = 0; i < tours.value[partId].list.length; i++) {
|
|
|
+ if (!tours.value[partId].list[i]._end) {
|
|
|
+ time += tours.value[partId].list[i].time - 0
|
|
|
+ if (!tours.value[partId].list[i]._notrans) {
|
|
|
+ time += 1000
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return time
|
|
|
+}
|
|
|
+
|
|
|
+const openTours = () => {
|
|
|
+ // showTours.value = !showTours.value
|
|
|
+ store.commit('tour/setData', { showTours: !showTours.value })
|
|
|
+ let bot = '0px'
|
|
|
+ if (showTours.value) {
|
|
|
+ bot = '120px'
|
|
|
+ } else {
|
|
|
+ bot = '0px'
|
|
|
+ }
|
|
|
+ store.commit('setControlsBottom', bot)
|
|
|
+ nextTick(() => {
|
|
|
+ if (isPlay.value) {
|
|
|
+ slideScroll()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+const changeFrame = async (type, id) => {
|
|
|
+ store.commit('tag/closeTag')
|
|
|
+ progressNum.value = 0
|
|
|
+ let player = await getApp().TourManager.player
|
|
|
+ if (type == 1) {
|
|
|
+ Track('view-tour', {
|
|
|
+ eventType: 'click',
|
|
|
+ click: 'part',
|
|
|
+ })
|
|
|
+ store.commit('tour/setData', {
|
|
|
+ frameId: 0,
|
|
|
+ partId: id,
|
|
|
+ })
|
|
|
+ progressNum.value = 0
|
|
|
+
|
|
|
+ player.selectPart(id).then(() => {
|
|
|
+ if (!isPlay.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ store.commit('tour/setData', {
|
|
|
+ isPlay: true,
|
|
|
+ })
|
|
|
+ player.play(id, frameId.value)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Track('view-tour', {
|
|
|
+ eventType: 'click',
|
|
|
+ click: 'frame',
|
|
|
+ })
|
|
|
+
|
|
|
+ store.commit('tour/setData', {
|
|
|
+ frameId: id,
|
|
|
+ })
|
|
|
+ progressNum.value = 0
|
|
|
+ player.selectFrame(id).then(() => {
|
|
|
+ if (!isPlay.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ store.commit('tour/setData', {
|
|
|
+ isPlay: true,
|
|
|
+ })
|
|
|
+ player.play(0, id)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ slideScroll()
|
|
|
+}
|
|
|
+const onClickHandler = async () => {
|
|
|
+ if (isPlay.value) {
|
|
|
+ let player = await getApp().TourManager.player
|
|
|
+ player.pause()
|
|
|
+ musicPlayer.resume()
|
|
|
+ }
|
|
|
+}
|
|
|
+onMounted(() => {
|
|
|
+ useApp().then(app => {
|
|
|
+ hanlderTour()
|
|
|
+ })
|
|
|
+
|
|
|
+ nextTick(() => {
|
|
|
+ let player = document.querySelector('.player[name="main"]')
|
|
|
+ player.addEventListener('pointerdown', onClickHandler)
|
|
|
+ })
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.tours-captions {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 64px;
|
|
|
+ left: 20px;
|
|
|
+ width: 480px;
|
|
|
+ word-break: break-all;
|
|
|
+ text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
|
|
|
+ text-align: justify;
|
|
|
+ color: #fff;
|
|
|
+ pointer-events: none;
|
|
|
+ z-index: 1;
|
|
|
+ transition: all 0.3s;
|
|
|
+ &.active {
|
|
|
+ // bottom: 184px;
|
|
|
+ }
|
|
|
+ .captions-title {
|
|
|
+ font-size: 28px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .captions-desc {
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 24px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.controls-left-buttons {
|
|
|
+ // margin-left: 20px;
|
|
|
+ // margin-bottom: 20px;
|
|
|
+ display: flex;
|
|
|
+ // justify-content: center;
|
|
|
+ align-items: flex-end;
|
|
|
+ padding: 0 0 20px 20px;
|
|
|
+}
|
|
|
+.buttons.tour {
|
|
|
+ margin-right: 10px;
|
|
|
+ > div {
|
|
|
+ margin-left: 0px;
|
|
|
+ margin-right: 0px;
|
|
|
+ padding: 0 10px;
|
|
|
+ &.show-list {
|
|
|
+ border-left: solid 1px var(--editor-font-color);
|
|
|
+ }
|
|
|
+ .icon-pull-down {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ span {
|
|
|
+ right: -10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.tour-list {
|
|
|
+ width: 100%;
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex: 1;
|
|
|
+ // height: var(--editor-toolbar-height);
|
|
|
+ height: 120px;
|
|
|
+ background-color: var(--editor-menu-back);
|
|
|
+ pointer-events: all;
|
|
|
+ left: var(--editor-toolbox-left);
|
|
|
+ z-index: 1;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ &::after {
|
|
|
+ width: 100%;
|
|
|
+ position: absolute;
|
|
|
+ content: '';
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ border-bottom: solid 1px rgba(255, 255, 255, 0.16);
|
|
|
+ border-top: solid 1px #000;
|
|
|
+ }
|
|
|
+ &.ban {
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+ .part-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ overflow: hidden;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ .part-list {
|
|
|
+ width: 100%;
|
|
|
+ height: 120px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-start;
|
|
|
+ padding: 0 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ .part-item {
|
|
|
+ width: 120px;
|
|
|
+ height: 80px;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 10px;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-size: 100%;
|
|
|
+ background-position: center;
|
|
|
+ &:last-of-type {
|
|
|
+ margin-right: 0px;
|
|
|
+ }
|
|
|
+ &:hover {
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+ .precent {
|
|
|
+ width: 0%;
|
|
|
+ height: 3px;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ background: var(--editor-main-color);
|
|
|
+ // opacity: 0.4;
|
|
|
+ z-index: 100;
|
|
|
+ // transition: width 0.1s;
|
|
|
+ }
|
|
|
+ .part-title {
|
|
|
+ width: 100%;
|
|
|
+ height: 24px;
|
|
|
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0.5) 100%);
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 14px;
|
|
|
+ z-index: 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.play-control {
|
|
|
+ pointer-events: all;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 34px;
|
|
|
+ border-radius: 17px;
|
|
|
+ // background-color: rgba(0, 0, 0, 0.3);
|
|
|
+ min-width: 34px;
|
|
|
+ border-radius: 17px;
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ // margin-left: 10px;
|
|
|
+
|
|
|
+ .tour-btn {
|
|
|
+ width: 34px;
|
|
|
+ height: 22px;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ > .iconfont {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ &.play-btn {
|
|
|
+ // border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
+ // > .iconfont {
|
|
|
+ // font-size: 20px;
|
|
|
+ // transition: rotate 0.3s;
|
|
|
+ // }
|
|
|
+ position: relative;
|
|
|
+ .animation-icon {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ // background: red;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position: 0% 0%;
|
|
|
+ background-size: auto 24px;
|
|
|
+ &:hover {
|
|
|
+ .tip {
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tip {
|
|
|
+ color: white;
|
|
|
+ position: absolute;
|
|
|
+ transform-origin: top center;
|
|
|
+ background: #000000;
|
|
|
+ border-radius: 4px;
|
|
|
+ opacity: 0;
|
|
|
+ padding: 10px;
|
|
|
+ margin: 10px;
|
|
|
+ font-size: 12px;
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
+ pointer-events: none;
|
|
|
+ white-space: nowrap;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ margin-left: 0;
|
|
|
+ margin-right: 0;
|
|
|
+ z-index: 10;
|
|
|
+ bottom: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.action {
|
|
|
+ animation: humanAction 1s steps(25) infinite;
|
|
|
+ }
|
|
|
+ @keyframes humanAction {
|
|
|
+ 0% {
|
|
|
+ background-position: 0% 0%;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ background-position: 100% 0%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.bor {
|
|
|
+ height: 16px;
|
|
|
+ border-right: 1px solid;
|
|
|
+ border-image: linear-gradient(to bottom, rgba(194, 194, 194, 0.3), rgba(255, 255, 255, 0.3)) 1;
|
|
|
+
|
|
|
+ padding: 0 34px;
|
|
|
+ cursor: default;
|
|
|
+ > .iconfont {
|
|
|
+ font-size: 18px;
|
|
|
+ transform: rotate(180deg);
|
|
|
+ cursor: pointer;
|
|
|
+ &.active {
|
|
|
+ transform: rotate(0deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|