|
@@ -1,5 +1,317 @@
|
|
|
<template>
|
|
|
<div class="hotspot-icon-serial-frame">
|
|
|
- 序列帧
|
|
|
+ <button
|
|
|
+ v-if="!selectedIcon"
|
|
|
+ class="add-icon"
|
|
|
+ @click="isShowSelectionWindow = true"
|
|
|
+ >
|
|
|
+ <img src="@/assets/images/default/hotspot_scene_add.png" alt="">
|
|
|
+ <div class="button-name">添加图标</div>
|
|
|
+ <div class="tip">最大宽度:300px,高度不限</div>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <div v-if="selectedIcon" class="icon-selected">
|
|
|
+ <div
|
|
|
+ class="icon-wrap"
|
|
|
+ :style="{
|
|
|
+ height: frameHeight ? frameHeight + 'px' : '',
|
|
|
+ width: frameWidth ? frameWidth + 'px' : '',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ class="serial-frame-preview"
|
|
|
+ ref="serial-frame-preview"
|
|
|
+ :src="selectedIcon"
|
|
|
+ alt=""
|
|
|
+ :style="{
|
|
|
+ top: -this.frameHeight * this.currentFrameIdx + 'px',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <button class="delete-btn" @click="onClickDelete">
|
|
|
+ <img class="normal" src="@/assets/images/icons/close01_normal@2x.png" alt="">
|
|
|
+ <img class="hover" src="@/assets/images/icons/close01_hover@2x.png" alt="">
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="right-wrap">
|
|
|
+ <button class="select-icon ui-button submit" @click="isShowSelectionWindow = true">选择图标</button>
|
|
|
+ <div class="tip">最大宽度:300px,高度不限</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="frame-num-setting serial-setting-item">
|
|
|
+ <div class="remark">序列帧总帧数</div>
|
|
|
+ <div class="right-wrap">
|
|
|
+ <input
|
|
|
+ v-model.trim.number="frameNumber"
|
|
|
+ @blur="onFrameNumberInputBlur"
|
|
|
+ type="number"
|
|
|
+ min="2"
|
|
|
+ step="1"
|
|
|
+ />
|
|
|
+ <span>帧</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="duration-setting serial-setting-item">
|
|
|
+ <div class="remark">总播放时长</div>
|
|
|
+ <div class="right-wrap">
|
|
|
+ <input
|
|
|
+ v-model.trim.number="duration"
|
|
|
+ @blur="onDurationInputBlur"
|
|
|
+ type="number"
|
|
|
+ min="0"
|
|
|
+ />
|
|
|
+ <span>秒</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="dialog" style="z-index: 2000" v-if="isShowSelectionWindow">
|
|
|
+ <MaterialSelector
|
|
|
+ :title="$i18n.t(`gather.select_material`)"
|
|
|
+ @cancle="isShowSelectionWindow = false"
|
|
|
+ @submit="handleSubmitFromMaterialSelector"
|
|
|
+ :selectableType="['image']"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
-</template>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { mapGetters } from "vuex";
|
|
|
+
|
|
|
+import MaterialSelector from "@/components/materialSelector.vue";
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ MaterialSelector,
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ selectedIcon: null,
|
|
|
+ isShowSelectionWindow: false,
|
|
|
+
|
|
|
+ frameNumber: 30,
|
|
|
+ duration: 3,
|
|
|
+
|
|
|
+ frameHeight: 0,
|
|
|
+ frameWidth: 0,
|
|
|
+ currentFrameIdx: 0,
|
|
|
+ intervalId: null,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ frameNumber: {
|
|
|
+ handler(vNew) {
|
|
|
+ if (vNew >= 2 && Number.isInteger(vNew)) {
|
|
|
+ this.computeFrameHeight()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ frameHeight: {
|
|
|
+ handler() {
|
|
|
+ this.playSerialFrame()
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ duration: {
|
|
|
+ handler() {
|
|
|
+ this.playSerialFrame()
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onFrameNumberInputBlur() {
|
|
|
+ if (this.frameNumber < 2) {
|
|
|
+ this.frameNumber = 2
|
|
|
+ } else {
|
|
|
+ this.frameNumber = Math.round(this.frameNumber)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onDurationInputBlur() {
|
|
|
+ if (this.duration < 0) {
|
|
|
+ this.duration = 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleSubmitFromMaterialSelector(data) {
|
|
|
+ this.isShowSelectionWindow = false
|
|
|
+ this.selectedIcon = data[0].icon
|
|
|
+
|
|
|
+ this.computeFrameHeight()
|
|
|
+ },
|
|
|
+ computeFrameHeight() {
|
|
|
+ this.frameHeight = 0
|
|
|
+ this.frameWidth = 0
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ try {
|
|
|
+ this.frameHeight = this.$refs['serial-frame-preview'].clientHeight / this.frameNumber
|
|
|
+ if (this.frameHeight > 110) {
|
|
|
+ this.frameWidth = 110 * 110 / this.frameHeight
|
|
|
+ this.frameHeight = 110
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ this.frameHeight = 0
|
|
|
+ this.frameWidth = 0
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ playSerialFrame() {
|
|
|
+ clearInterval(this.intervalId)
|
|
|
+ this.currentFrameIdx = 0
|
|
|
+ if (!this.selectedIcon || this.frameHeight <= 0 || this.duration <= 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.intervalId = setInterval(() => {
|
|
|
+ this.currentFrameIdx++
|
|
|
+ if (this.currentFrameIdx >= this.frameNumber) {
|
|
|
+ this.currentFrameIdx = 0
|
|
|
+ }
|
|
|
+ }, this.duration / this.frameNumber * 1000);
|
|
|
+ this.$emit('addHotspot', {
|
|
|
+ type: 'serial_frame',
|
|
|
+ img: this.selectedIcon,
|
|
|
+ serialFrameInfo: {
|
|
|
+ frameNumber: this.frameNumber,
|
|
|
+ duration: this.duration
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ },
|
|
|
+ onClickDelete() {
|
|
|
+ this.selectedIcon = null
|
|
|
+ clearInterval(this.intervalId)
|
|
|
+ this.frameHeight = 0
|
|
|
+ this.frameWidth = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.hotspot-icon-serial-frame {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ > button.add-icon {
|
|
|
+ width: 100%;
|
|
|
+ height: 110px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ background: #1A1B1D;
|
|
|
+ border-radius: 2px;
|
|
|
+ border: 1px solid #404040;
|
|
|
+ cursor: pointer;
|
|
|
+ > img {
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+ > .button-name {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #0076F6;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+ > .tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(255, 255, 255, 0.3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ > .icon-selected {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ > .icon-wrap {
|
|
|
+ width: 110px;
|
|
|
+ height: 110px;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ border-radius: 2px;
|
|
|
+ > .serial-frame-preview {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ > .delete-btn {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ padding: 0;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ .normal {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ .hover {
|
|
|
+ display: initial;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > .normal {
|
|
|
+ display: initial;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ > .hover {
|
|
|
+ display: none;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > .right-wrap {
|
|
|
+ width: 108px;
|
|
|
+ > button.select-icon {
|
|
|
+ margin-bottom: 14px;
|
|
|
+ }
|
|
|
+ > .tip {
|
|
|
+ font-size: 14px;
|
|
|
+ color: rgba(255,255,255,0.3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ > .serial-setting-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ &:first-of-type {
|
|
|
+ margin-top: 16px;
|
|
|
+ margin-bottom: 10px;;
|
|
|
+ }
|
|
|
+ > .remark {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #ababab;
|
|
|
+ }
|
|
|
+ > .right-wrap {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ > input {
|
|
|
+ width: 60px;
|
|
|
+ height: 36px;
|
|
|
+ background: #1A1B1D;
|
|
|
+ border-radius: 2px;
|
|
|
+ border: 1px solid #404040;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #FFFFFF;
|
|
|
+ margin-right: 10px;
|
|
|
+ padding-left: 16px;
|
|
|
+ &:focus {
|
|
|
+ border-color: @color;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > span {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #ababab;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|