自定义时间轴组件

前言

开发工作中常常有一个通过启动时间轴切换地图图层切换的功能需求,但是又很难找到一个满足要求的时间轴,所以自己撸了一个,目前还有一些功能需要改进,这里先记录一下代码

代码

* AnimationSlider.vue 可以播放的timeLine
* @Author ZhangJun
* @Date  2024/2/20 16:08
**/
<template>
  <div class="animationSliderContainer flex">
    <a-space :size="5" style="padding: 5px 10px;margin: auto;" direction="vertical">
      <slot name="operation">
        <a-space>
          <a-popover content="上一个">
            <a-button type="primary" @click="preTickItem()" :icon="isLoading?'loading':'step-backward'"></a-button>
          </a-popover>
          <a-popover content="开始/暂停">
            <a-button type="primary" @click="onPlay()" :icon="isLoading?'loading':(isStartPlay?'pause':'caret-right')"
            ></a-button>
          </a-popover>
          <a-popover content="下一个">
            <a-button type="primary" @click="nextTickItem()" :icon="isLoading?'loading':'step-forward'"></a-button>
          </a-popover>
          <a-popover content="重播">
            <a-button type="primary" @click="onReset()" :icon="isLoading?'loading':'reload'"></a-button>
          </a-popover>
          <a-divider type="vertical" style="margin: 0;height: 24px;"/>
          <a-popover :content="isAutoUpdate?'关闭自动更新':'开启自动更新'">
            <a-button :type="isAutoUpdate? 'primary':''"
                      @click="onAutoUpdate()"
                      :icon="isLoading?'loading':'sync'"></a-button>
          </a-popover>
        </a-space>
      </slot>

      <slot name="currentDateTime" :dateTime="getCurrentDateTime">
        <div :style="{color:tickColor,fontSize:'18px'}">{{ getCurrentDateTime }}</div>
      </slot>
    </a-space>

    <div class="tickBox relative" ref="tickBox" :style="{height:hourTickHeight+75+'px',width:'calc(100% - 180px)'}">
      <!--过去/未来标记-->
      <a-space size="0"
               class="relative text-white"
               :style="{left:this.nowDateTimeMarkPosition}"
               style="width: 0;height:0;bottom:0;">
        <template v-if="isShowNowDateTimeMark">
          <span style="white-space: nowrap;color: #84a4de">过去</span>
          <a-icon type="caret-left"/>
          <div class="divider_now"></div>
          <a-icon type="caret-right"/>
          <span style="white-space: nowrap;color: #92d292">未来</span>
        </template>
        <div v-else></div>
      </a-space>

      <a-space :size="0" style="position: absolute;top:25px;">
        <template v-for="(item,index) in getTicks">
          <div>
            <!--刻度-->
            <div class="tick_l">
              <!--里面的小刻度-->
              <template v-for="(t,i) in item.values">
                <div class="flex">
                  <a-popover :key="i">
                    <template slot="content">
                      {{ moment(t.dateTime, 'YYYYMMDDHHmm').format('YYYY-MM-DD HH:mm') }}
                    </template>

                    <a-space :size="0">
                      <div class="tick_s"
                           :style="getActiveTickItemStyle(t)"
                           @click="onClickTickItem(t)"></div>
                      <div class="divider_sm" v-if="item.values.length-1>i"></div>
                    </a-space>
                  </a-popover>
                </div>
              </template>

              <!-- 上面的label-->
              <div class="divider_lg" v-if="item.label" :style="{backgroundColor: dayTickColor}">
                <div class="relative"
                     :style="{left:(item.label.length/2)*(-9.5)+'px',top:'-24px',whiteSpace:'nowrap',color:tickTextColor}">
                  {{ item.label }}
                </div>
              </div>

              <!--下面的刻度提示-->
              <div class="divider_lg"
                   v-else-if="moment(item.values[item.values.length-1].dateTime,'YYYYMMDDHHmm').minutes()===0">
                <span v-if="item.tickName"
                      class="relative"
                      :style="{left:(item.tickName.length/2)*(-9.5)+'px',bottom:`-${hourTickHeightPix}`,whiteSpace:'nowrap',color:tickTextColor}">
                  {{ item.tickName }}
                </span>
              </div>

              <div class="divider_lg_transparent" v-else>

              </div>
            </div>
          </div>
        </template>
      </a-space>

      <!--当前时刻显示-->
      <div class="relative"
           style="border-radius: 2px;width: fit-content;padding: 0 4px 0 0;"
           :style="{backgroundColor:activeTickColor,left:getActiveItemPosition,bottom:`calc(-${hourTickHeightPix} * 1.9)`,color:tickTextColor}">
        <a-space :size="4">
          <a-icon style="width: 12px;" type="caret-up"/>
          <div>
            {{ getCurrentDateTimeStr() }}
          </div>
        </a-space>
      </div>
    </div>
  </div>
</template>

<script>
import moment from "moment";
import BigNumber from "bignumber.js";
import _ from "lodash";

export default {
  name: "AnimationSlider",
  emits: ['update:modelValue', 'nowDateTimeUpdate'],
  props: {
    /**
     * 标准线时间(可以根据时间的粒度控制开始时间的粒度,比如 “YYYYMMDDHHmm”就会精确到分钟,如果想要精确到小时就用 “YYYYMMDDHH”)
     */
    standardLineDateTime: {type: String, default: moment().format('YYYYMMDDHHmm')},
    /**
     * 每个单位刻度代表的小时数
     */
    precision: {type: Number, default: 0.5},
    /**
     * 时间段的分布(前面2天,后面2天)
     */
    daysSpan: {Type: Array, default: () => ([2, 2])},
    /**
     * 刻度值显示的范围距离(小时)
     */
    hourly: {type: Number, default: 3},
    /**
     * 播放间隔时间
     */
    timeout: {type: Number, default: 500},

    /**
     * 每个刻度的width
     */
    tickWidth: {type: Number, default: 10},

    /**
     * 每个刻度的height
     */
    tickHeight: {type: Number, default: 8},

    /**
     * 刻度线的颜色
     */
    tickColor: {type: String, default: 'white'},//
    /**
     * 单位刻度填充的颜色
     */
    tickFillColor: {type: String, default: '#afb9cc'},

    /**
     * 背景的颜色
     */
    tickBgColor: {type: String, default: '#5b5d60'},

    /**
     * 文字的颜色
     */
    tickTextColor: {type: String, default: 'white'},

    /**
     * 显示小时刻度的颜色
     */
    hourTickColor: {type: String, default: 'white'},

    /**
     * 显示小时刻度的height
     */
    hourTickHeight: {type: Number, default: 20},

    /**
     * 显示日期刻度的颜色
     */
    dayTickColor: {type: String, default: '#92d292'},

    /**
     * 显示日期刻度的颜色
     */
    activeTickColor: {type: String, default: '#6a98ea'},

    /**
     * 当前时间刻度的height
     */
    nowTickHeight: {type: Number, default: 50},

    /**
     * 当前时间刻度的color
     */
    nowTickColor: {type: String, default: '#6a98ea'},

    /**
     * 当前时间轴的边框颜色
     */
    borderColor: {type: String, default: '#0E4C8F'},

    /**
     * 格式化单个刻度的数据方法
     */
    tickItemFormat: {type: Function, default: null},

    /**
     * v-model双向绑定的值(modelValue如果不是刻度值,就会重新设置双向绑定的值为一个合理的刻度值,处理逻辑的函数是initActiveItems())
     */
    modelValue: {type: Array, default: () => ([moment().format('YYYYMMDDHHmm')])},
    /**
     * 自定更新时间(小时)
     */
    autoUpdateInterval: {type: Number, default: undefined},
    /**
     * 加载状态
     */
    isLoading: {type: Boolean, default: false},
    /**
     * 是否显示当前时间marker
     */
    isShowNowDateTimeMark: {type: Boolean, default: true}
  },
  model: {
    prop: 'modelValue',
    event: 'update:modelValue'
  },
  data() {
    return {
      moment: moment,
      startTick: 0,//开始的刻度值
      nowDateTime: null,//标准线
      startDateTime: null,
      endDateTime: null,
      totalHours: 24,//一共展示的小时
      activeItems: null,//处于激活状态的tickItem集合
      isStartPlay: false,
      setIntervalHandler: null,
      scrollInterval: null,
      tickWidthValue: this.tickWidth + 'px',
      tickHeightValue: this.tickHeight + 'px',
      nowDateTimeMarkPosition: {},//当前时间的marker的位置
      updateNowDateTimeMarkPositionHandler: null,//自动更新当前时间的handler
      nowTickHeightPix: `${this.nowTickHeight}px`,
      hourTickHeightPix: `${this.hourTickHeight}px`,
      isAutoUpdate: !isNaN(this.autoUpdateInterval)//如果有更新间隔时间就开启自动更新提醒
    }
  },
  computed: {
    getTicks() {
      let ticks = [];
      //起始时间
      let startDateTime = moment(this.startDateTime, 'YYYYMMDDHHmm');
      //如果其实时间不是整小时,这个分钟的值就要做特殊处理
      let minutes = startDateTime.minutes();
      //将不是整小时的部分换算成小时值
      let dummyValue = new BigNumber(minutes).div(60).toNumber();
      //刻度的初始值
      let current = dummyValue || this.startTick;

      let tick_l = {values: []};
      let totalHours = new BigNumber(this.totalHours).plus(current).toNumber();
      while (current <= totalHours) {
        //加一个刻度的值
        current = new BigNumber(current).plus(this.precision).toNumber();
        if (!tick_l?.values) {
          tick_l.values = [];
        }

        //累加一个刻度的时间(小时)
        let dateTimeVal = startDateTime.add(this.precision, 'hour');
        //当前这个刻度代表的时间
        dateTimeVal = dateTimeVal.format('YYYYMMDDHHmm');
        //填充当前这个刻度的时间,还有值
        let tickItem = {value: current, dateTime: dateTimeVal};
        //当前这个大刻度(1小时)里面包含的所有小刻度的值
        tick_l.values = [...tick_l.values, tickItem]

        //如果是整数(满小时数)
        if (Number.isInteger(current)) {
          ticks = [...ticks, tick_l];
          //为下一个大刻度存值做准备
          tick_l = {values: []};
        }
      }

      //如果还不满小时
      if (tick_l?.values?.length > 0) {
        //是否精确到分钟
        let isPreciseMinutes = moment(this.standardLineDateTime, 'YYYYMMDDHHmm').minutes() > 0;
        if (isPreciseMinutes) {
          ticks = [...ticks, tick_l];
        }
      }
      //如果有格式化的方法就格式化刻度的数据源,并且提供刻度的tickName和label
      ticks = this.defaultFormat(ticks, dummyValue);
      return ticks;
    },
    //得到当前选择的时间
    getCurrentDateTime() {
      if (this?.activeItems?.length > 1) {
        let [startItem] = this?.activeItems;
        let endItem = this?.activeItems[this.activeItems.length - 1];
        let startDateTime_temp = moment(startItem.dateTime, 'YYYYMMDDHHmm').format('YYYY年MM月DD日 HH:mm');
        let endDateTime_temp = moment(endItem.dateTime, 'YYYYMMDDHHmm').format('YYYY年MM月DD日 HH:mm');
        return `${startDateTime_temp} ~ ${endDateTime_temp}`;
      } else if (this?.activeItems?.length === 1) {
        let [{dateTime}] = this?.activeItems;
        if (dateTime) {
          return moment(dateTime, 'YYYYMMDDHHmm').format('YYYY/MM/DD HH:mm');
        }
      }

      return '';
    },
    //当前选中的tickItem的left值
    getActiveItemPosition() {
      let [{dateTime}] = this?.activeItems || [{}];
      if (dateTime) {
        //计算当前时间跟起点时间的时间差
        let durationHours = moment.duration(moment(dateTime, 'YYYYMMDDHHmm').diff(moment(this.startDateTime, 'YYYYMMDDHHmm'))).asHours();

        //还要加上刻度线
        let tickWidth = new BigNumber(this.tickWidth).plus(1).toNumber();
        return new BigNumber(1).div(this.precision).times(tickWidth).times(durationHours).minus(tickWidth).toString() + 'px';
      }
    },
  },
  methods: {
    //初始化当前选中的刻度值
    initActiveItems() {
      this.activeItems = this.modelValue?.map((val) => {
        //如果初始值是一个不在刻度值的数值,就调整默认值
        val = this.formatValidDateTime(val);
        //计算当前时间跟起点时间的时间差
        let durationHours = moment.duration(moment(val, 'YYYYMMDDHHmm').diff(moment(this.startDateTime, 'YYYYMMDDHHmm'))).asHours();
        //这个时间所在的刻度位置索引
        let index = new BigNumber(durationHours).div(this.precision).toFixed(0);

        let [pre, end] = this.daysSpan;
        //一共有这么多的刻度
        let tickItemsCount = new BigNumber(pre).plus(end).times(24).div(this.precision).toFixed(2);

        if (tickItemsCount >= index) {
          return {dateTime: val, value: new BigNumber(index).times(this.precision).toNumber()};
        }
      }).filter((item) => !!item);

      if (this.activeItems?.length < 1) {
        this.activeItems = [{
          dateTime: moment(this.startDateTime, 'YYYYMMDDHHmm').add(this.precision, 'hours').format('YYYYMMDDHHmm'),
          value: 0
        }];
      }

      //滚动到默认选中的tickItem的位置
      let [{value}] = this.activeItems || [{}];
      if (value) {
        //还要加上刻度线
        let tickWidth = new BigNumber(this.tickWidth).plus(1);
        let tickBoxWidth = this?.$refs?.tickBox?.offsetWidth;
        //当前选中的这个item的索引
        let index = new BigNumber(value).div(this.precision);
        let scrollLeft = index.times(tickWidth).minus(tickBoxWidth * 0.5).toNumber();
        this.$nextTick(() => {
          this.$refs.tickBox.scrollBy(scrollLeft, 0);
        });
      }
    },
    //根据逐时格式化刻度数据(提供刻度的提示,还有自定义)
    defaultFormat(data = [], dummyValue = 0) {
      //遍历每一个大刻度(1小时)
      return data.map((item, index) => {
        index++;

        //减去虚拟加进去的值
        if (dummyValue > 0) {
          item.values = item?.values.map(val => {
            val.value = new BigNumber(val.value).minus(dummyValue).toNumber();
            return val;
          });
        }

        //取出最后一个小刻度的时间
        let {dateTime} = [...item.values].pop();
        dateTime = moment(dateTime, 'YYYYMMDDHHmm');

        //逐小时的数值(设置需要显示的刻度提示位置的提示)
        if (index % this.hourly === 0) {
          item.tickName = dateTime.format('HH') + '时';
        }

        //在整小时的刻度的位置添加label提示
        if (dateTime.format('HH') === '00') {
          item.label = dateTime.format('MM月DD日');
        }

        //如果有对单个刻度格式化的函数(这里是为了可以自定刻度的样式或者其他特性)
        if (typeof this.tickItemFormat === 'function') {
          item = this.tickItemFormat(item);
        }

        return item;
      });
    },
    //动态获取tick的样式
    getActiveTickItemStyle(tickItem) {
      let style_temp = tickItem?.style || {};
      let isActive = this?.activeItems?.findIndex(({dateTime}) => dateTime === tickItem?.dateTime) > -1;
      return isActive ? {...style_temp, backgroundColor: this.activeTickColor} : style_temp;
    },
    //点击tickItem事件回调
    onClickTickItem(tickItem) {
      this.activeItems = [tickItem];
      //停止播放
      this.isStartPlay = false;
      this.clearIntervalHandler();
    },
    clearIntervalHandler() {
      if (this.setIntervalHandler) {
        clearInterval(this.setIntervalHandler);
        this.setIntervalHandler = null;
      }

      this.isStartPlay = false;

      this.clearAutoScroll();
    },
    //刻度添加一个单位值
    addTickItemsValue({dateTime, value}) {
      if (dateTime) {
        dateTime = moment(dateTime, 'YYYYMMDDHHmm').add(this.precision, 'hour').format('YYYYMMDDHHmm');
        return {
          dateTime,
          value: new BigNumber(value).plus(this.precision).toNumber()
        }
      }
    },
    //刻度减少一个单位值
    subtractTickItemsValue({dateTime, value}) {
      if (dateTime) {
        dateTime = moment(dateTime, 'YYYYMMDDHHmm').subtract(this.precision, 'hour').format('YYYYMMDDHHmm');
        return {
          dateTime,
          value: new BigNumber(value).minus(this.precision).toNumber()
        }
      }
    },
    //回到上一个刻度
    preTickItem() {
      let preItems = this.activeItems.map((item) => {
        return this.subtractTickItemsValue(item);
      });

      //上一个item超过了起始时间
      if (preItems?.[0]?.dateTime <= this.startDateTime) {
        return;
      }
      this.activeItems = preItems;
    },
    //前进下一个刻度
    nextTickItem() {
      let nextItems = this.activeItems.map((item) => {
        return this.addTickItemsValue(item);
      });

      if (nextItems?.[0]?.dateTime > this.endDateTime) {
        //默认从头开始
        this.activeItems = [{dateTime: this.startDateTime, value: this.startTick}];
        this.nextTickItem();
      } else {
        this.activeItems = nextItems;
      }
    },
    //重新开始
    onReset() {
      this.clearAllInterval();

      //默认从头开始
      this.activeItems = [{dateTime: this.startDateTime, value: this.startTick}];
      this.isStartPlay = false;
      let days = this.daysSpan.reduce((a, b) => a + b);
      //一个小时表示的width
      let hourWidth = new BigNumber(1).div(this.precision).times(this.tickWidth);
      //这几天tick的总的width
      let sumWidth = new BigNumber(days).times(24).times(hourWidth);
      this.$refs.tickBox.scrollBy(-sumWidth, 0);

      this.onPlay();
    },
    //自动更新
    onAutoUpdate() {
      this.isAutoUpdate = !this.isAutoUpdate;
      if (this.isAutoUpdate) {
        this.startUpdateNowDateTimeMark();
      } else {
        this.clearUpdateNowDateTimeMark();
      }
    },
    onPlay() {
      this.isStartPlay = !this.isStartPlay;
      if (this.isStartPlay) {
        this.nextTickItem();

        let tickBoxWidth = this?.$refs?.tickBox?.offsetWidth;

        this.setIntervalHandler = setInterval(() => {
          this.nextTickItem();

          if (!this.scrollInterval) {
            this.startAutoScroll(tickBoxWidth);
          }
          //播放到最后的时候就停止
          if (this?.activeItems?.[0]?.dateTime === this.endDateTime) {
            this.clearIntervalHandler();
          }
        }, this.timeout);

      } else {
        this.clearIntervalHandler();
      }
    },
    //更新当前时间标记的位置
    updateNowDateTimeMarkPosition() {
      if (this.isShowNowDateTimeMark) {
        //计算当前时间跟起点时间的时间差
        let durationHours = moment.duration(moment().diff(moment(this.startDateTime, 'YYYYMMDDHHmm'))).asHours();

        //还要加上刻度线
        let tickWidth = new BigNumber(this.tickWidth).plus(1).toNumber();
        //这里的43就是标记的“过去”还有箭头图标的总width
        this.nowDateTimeMarkPosition = new BigNumber(1).div(this.precision).times(tickWidth).times(durationHours).minus(43).toString() + 'px';
      }
    },
    //开始滚动
    startAutoScroll(tickBoxWidth, timeout = this.timeout) {
      if (this?.$refs?.tickBox) {
        let [pre, next] = this.daysSpan;
        //一共有多少小时
        let totalHours = new BigNumber(pre).plus(next).times(24);
        //一个小时表示的width
        let hourWidth = new BigNumber(1).div(this.precision).times(this.tickWidth);
        //这几天tick的总的width
        let sumWidth = totalHours.times(hourWidth);
        //一共拥有多少个tickBox
        let count = sumWidth.div(tickBoxWidth);

        //还要加上刻度线
        let tickWidth = new BigNumber(this.tickWidth).plus(1).toNumber();

        timeout = new BigNumber(timeout).times(new BigNumber(1).div(count.minus(0.5)).plus(1));

        this.scrollInterval = setInterval(() => {
          this.$refs.tickBox.scrollBy(tickWidth, 0);
        }, timeout)
      }
    },
    //停止滚动
    clearAutoScroll() {
      if (this.scrollInterval) {
        clearInterval(this.scrollInterval);
        this.scrollInterval = null;
      }
    },
    //开始自动更新当前时间标记
    startUpdateNowDateTimeMark() {
      this.updateNowDateTimeMarkPosition();

      if (this.isAutoUpdate && this.isShowNowDateTimeMark) {
        let autoUpdateInterval = new BigNumber(this.autoUpdateInterval).times(3600000).toNumber();
        this.updateNowDateTimeMarkPositionHandler = setInterval(() => {
          this.updateNowDateTimeMarkPosition();
          //更新了当前时间的标记
          this.$emit('nowDateTimeUpdate');
        }, autoUpdateInterval);
      }
    },
    //停止自动更新当前时间标记
    clearUpdateNowDateTimeMark() {
      if (this.updateNowDateTimeMarkPositionHandler) {
        clearInterval(this.updateNowDateTimeMarkPositionHandler);
        this.updateNowDateTimeMarkPositionHandler = null;
      }
    },
    //格式化时间为有效的时间(需要在时间刻度上的值)
    formatValidDateTime(dateTime) {
      let standardLineDateTime = moment(dateTime, 'YYYYMMDDHHmm');
      //分钟
      let minutes = standardLineDateTime.format('mm');
      //一个刻度值代表的分钟值
      let t = new BigNumber(this.precision).times(60);
      //余数部分
      let remainder = Number(minutes) % t;
      //整数部分(向下取整,相当于是向前面的时间推)
      let integerVal = Math.floor(Number(minutes) / t);
      //时间不满一个刻度的部分就舍弃,向前取整(例如:12::05格式化后为12:00)
      if (remainder !== 0) {
        return standardLineDateTime.minutes(new BigNumber(integerVal).times(t).toNumber()).format('YYYYMMDDHHmm');
      }
      return dateTime;
    },
    init() {
      this.nowDateTime = this.formatValidDateTime(this.standardLineDateTime);

      //如果时间是精确到分钟的,我们计算起止时间都应该精确到分钟,否则就精确到小时
      let formatStr = moment(this.standardLineDateTime, 'YYYYMMDDHHmm').minute() > 0 ? 'YYYYMMDDHHmm' : 'YYYYMMDDHH';
      let [pre, next] = this.daysSpan;
      pre = new BigNumber(pre).times(24);
      next = new BigNumber(next).times(24);
      //一共有多少小时
      this.totalHours = pre.plus(next).toNumber();
      //获取开始时间
      this.startDateTime = moment(this.nowDateTime, formatStr).subtract(pre.toNumber(), 'hours').format('YYYYMMDDHHmm');
      //获取结束时间
      this.endDateTime = moment(this.nowDateTime, 'YYYYMMDDHH').add(next.toNumber(), 'hours').format('YYYYMMDDHHmm');

      //开始自动更新
      this.startUpdateNowDateTimeMark();
    },
    clearAllInterval() {
      this.clearUpdateNowDateTimeMark();
      this.clearIntervalHandler();
      this.clearAutoScroll();
    },
    //获取当前显示时间格式化后的字符
    getCurrentDateTimeStr(format = 'HH:mm') {
      if (this?.activeItems?.length > 1) {
        let [startItem] = this?.activeItems;
        let endItem = this?.activeItems[this.activeItems.length - 1];
        let startDateTime_temp = moment(startItem.dateTime, 'YYYYMMDDHHmm').format(format);
        let endDateTime_temp = moment(endItem.dateTime, 'YYYYMMDDHHmm').format(format);
        return `${startDateTime_temp} ~ ${endDateTime_temp}`;
      } else if (this?.activeItems?.length === 1) {
        let [{dateTime}] = this?.activeItems;
        if (dateTime) {
          return moment(dateTime, 'YYYYMMDDHHmm').format(format);
        }
      }

      return '';
    },
  },
  created() {
    this.init();
  },
  mounted() {
    this.initActiveItems();
  },
  destroyed() {
    this.clearAllInterval();
  },
  watch: {
    activeItems: {
      handler(newVal, oldVal) {
        if (!_.isEqual(newVal, oldVal)) {
          this.$emit('update:modelValue', newVal?.map(({dateTime}) => dateTime));
        }
      },
      immediate: false
    },
    standardLineDateTime: {
      handler(newVal, oldVal) {
        if (!_.isEqual(newVal, oldVal)) {
          this.init();
        }
      },
      immediate: false,
    }
  }
}
</script>

<style lang="less" scoped>
@borderColor: v-bind(borderColor);
@tickHeight: v-bind(tickHeightValue);
@tickWidth: v-bind(tickWidthValue);
@tickColor: v-bind(tickColor);
@hourTickColor: v-bind(hourTickColor);
@tickBgColor: v-bind(tickBgColor);
@tickFillColor: v-bind(tickFillColor);
@nowTickHeight: v-bind(nowTickHeightPix);
@nowTickColor: v-bind(nowTickColor);
@hourTickHeight: v-bind(hourTickHeightPix);

.animationSliderContainer {
  border: 1px solid @borderColor;
  background-color: @tickBgColor;
  width: 100%;
  overflow: hidden;

  /* 滚动条样式 */

  ::-webkit-scrollbar {
    width: 8px; /* 设置滚动条宽度 */
    height: 8px; /* 设置滚动条高度 */
  }

  ::-webkit-scrollbar-thumb {
    background-color: #999; /* 设置滑块背景色 */
    border-radius: 2px; /* 设置滑块边角圆角程度 */
  }

  ::-webkit-scrollbar-track {
    background-color: #f1f1f1; /* 设置滚动条轨道背景色 */
    border-radius: 0; /* 设置滚动条轨道边角圆角程度 */
  }

  ::-webkit-scrollbar-button {
    display: none; /* 不显示按钮 */
  }
}

.tickBox {
  border-left: 1px solid @borderColor;
  overflow: auto;
  padding: 5px 0;
}

.tick_l {
  display: flex;
  align-items: flex-end;
}

.tick_s {
  width: @tickWidth;
  height: @tickHeight;
  background-color: @tickFillColor;
}

.divider_lg {
  height: @hourTickHeight;
  width: 1px;
  background-color: @hourTickColor;
}

.divider_lg_transparent {
  height: @hourTickHeight;
  width: 1px;
  background-color: transparent;
}

.divider_sm {
  height: @tickHeight;
  width: 1px;
  background-color: @tickColor;
}

.divider_now {
  height: @nowTickHeight;
  width: 1px;
  background-color: @nowTickColor;
}

.flex {
  display: flex;
}

.w-full {
  width: 100%;
}

.text-right {
  text-align: right;
}

.relative {
  position: relative;
}

.text-white {
  color: white;
}

/deep/ .ant-btn {
  .anticon {
    line-height: 0;
  }
}
</style>

参数说明

  props: {
       /**
     * 标准线时间(可以根据时间的粒度控制开始时间的粒度,比如 “YYYYMMDDHHmm”就会精确到分钟,如果想要精确到小时就用 “YYYYMMDDHH”)
     */
    standardLineDateTime: {type: String, default: moment().format('YYYYMMDDHHmm')},
    /**
     * 每个单位刻度代表的小时数
     */
    precision: {type: Number, default: 0.5},
    /**
     * 时间段的分布(前面2天,后面2天)
     */
    daysSpan: {Type: Array, default: () => ([2, 2])},
    /**
     * 刻度值显示的范围距离(小时)
     */
    hourly: {type: Number, default: 3},
    /**
     * 播放间隔时间
     */
    timeout: {type: Number, default: 500},

    /**
     * 每个刻度的width
     */
    tickWidth: {type: Number, default: 10},

    /**
     * 每个刻度的height
     */
    tickHeight: {type: Number, default: 8},

    /**
     * 刻度线的颜色
     */
    tickColor: {type: String, default: 'white'},//
    /**
     * 单位刻度填充的颜色
     */
    tickFillColor: {type: String, default: '#afb9cc'},

    /**
     * 背景的颜色
     */
    tickBgColor: {type: String, default: '#5b5d60'},

    /**
     * 文字的颜色
     */
    tickTextColor: {type: String, default: 'white'},

    /**
     * 显示小时刻度的颜色
     */
    hourTickColor: {type: String, default: 'white'},

    /**
     * 显示小时刻度的height
     */
    hourTickHeight: {type: Number, default: 20},

    /**
     * 显示日期刻度的颜色
     */
    dayTickColor: {type: String, default: '#92d292'},

    /**
     * 显示日期刻度的颜色
     */
    activeTickColor: {type: String, default: '#6a98ea'},

    /**
     * 当前时间刻度的height
     */
    nowTickHeight: {type: Number, default: 50},

    /**
     * 当前时间刻度的color
     */
    nowTickColor: {type: String, default: '#6a98ea'},

    /**
     * 当前时间轴的边框颜色
     */
    borderColor: {type: String, default: '#0E4C8F'},

    /**
     * 格式化单个刻度的数据方法
     */
    tickItemFormat: {type: Function, default: null},

    /**
     * v-model双向绑定的值(modelValue如果不是刻度值,就会重新设置双向绑定的值为一个合理的刻度值,处理逻辑的函数是initActiveItems())
     */
    modelValue: {type: Array, default: () => ([moment().format('YYYYMMDDHHmm')])},
    /**
     * 自定更新时间(小时)
     */
    autoUpdateInterval: {type: Number, default: undefined},
    /**
     * 加载状态
     */
    isLoading: {type: Boolean, default: false},
    /**
     * 是否显示当前时间marker
     */
    isShowNowDateTimeMark: {type: Boolean, default: true}
  }

使用

     <animation-slider :days-span="[0.125,0.125]"
                        :precision="0.1"
                        :tick-width="25"
                        :tick-height="10"
                        :hourly="1"
                        :timeout="playTimeout"
                        :standard-line-date-time="moment(nowDateTime,'YYYYMMDDHHmm').format('YYYYMMDDHH')"
                        :tick-item-format="tickItemFormat"
                        :auto-update-interval="0.03"
                        @nowDateTimeUpdate="onNowDateTimeUpdate"
                        :is-loading="isLoading"
                        ref="timeline"
                        v-model="activeDateTime"></animation-slider>

效果

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花姐夫Jun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值