123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- <template>
- <div :ref="'timeline-' + guid" class="timeline" ondragstart="return false;" onselectstart="return false;">
- <p class="timeline-line"></p>
- <div
- ref="timeline-main"
- class="timeline-main"
- :key="'timeline-main-' + guid"
- :id="'timeline-main-' + guid"
- >
- <!-- 时间段 -->
- <span
- v-for="item in timeArr"
- :key="item + guid"
- :class="'timeline-text-' + guid"
- :style="{ paddingRight: paddingRight + 'px' }"
- >{{ item }}</span>
- <!-- 录像片段的背景,层级-1 -->
- <div class="record-bg-div">
- <span class="record-bg-span" v-for="(record, index) in recordRange" :key="index + guid" :style="{ left: record.left + 'px', width: record.width + 'px' }"></span>
- </div>
- </div>
- </div>
- </template>
- <script>
- module.exports = {
- data() {
- return {
- // 时间段数组,不同时间间隔,时间段的数量和值都是不同的
- timeArr: [],
- // 时间间隔范围对应的下标
- intervalNum: 6,
- // 时间间隔范围对应的秒数,从1分钟到2小时
- intervalArr: [60, 300, 600, 900, 1800, 3600, 7200],
- paddingRight: 50,
- timer: null,
- // 时间轴所选时间,默认显示12点的位置
- selectTime: "12:00:00",
- guid: "",
- parentWidth: 0,
- resizeFn: null,
- // 录像片段的区间信息,包括开始时间结束时间,左边距和宽度
- recordRange: [],
- // 上次背景设置日期
- lastBgSetDate: ''
- };
- },
- props: {
- // 录像片段
- recordInfos: {
- type: Array,
- default() {
- return []
- }
- }
- },
- watch: {
- // 所选时间变化,触发父页面时间点变化方法
- selectTime: {
- handler(val) {
- if (val) {
- this.$emit("timer-change", val);
- }
- },
- },
- // 录像片段变化时,重新设置背景
- recordInfos: {
- deep: true,
- handler(val) {
- if (val && val.length > 0) {
- // windowTime格式:2021-07-02 12:10:30
- this.lastBgSetDate = val[0].windowTime.split(" ")[0]
- this.setBackground(val)
- } else {
- this.recordRange = []
- }
- }
- }
- },
- computed: {
- // 最小右间距
- minRight() {
- return Math.ceil(this.parentWidth * 0.03);
- },
- // 最大右间距
- maxRight() {
- return Math.ceil(this.parentWidth * 0.09);
- },
- },
- methods: {
- // 时间秒数格式化
- secToTime(s) {
- s = Math.floor(s)
- var t;
- if (s > -1) {
- var hour = Math.floor(s / 3600);
- var min = Math.floor(s / 60) % 60;
- var sec = s % 60;
- if (hour < 10) {
- t = "0" + hour + ":";
- } else {
- t = hour + ":";
- }
- if (min < 10) {
- t += "0";
- }
- t += min + ":";
- if (sec < 10) {
- t += "0";
- }
- t += sec;
- }
- return t === '24:00:00' ? '23:59:59' : t;
- },
- // 时间转成秒数
- timeToSec(time) {
- let arr = time.split(":")
- let hour = parseInt(arr[0])
- let min = parseInt(arr[1])
- let sec = parseInt(arr[2])
- return hour * 3600 + min * 60 + sec;
- },
- // 定位时间,父页面使用
- positionTime(time) {
- let second = this.timeToSec(time);
- let left = second / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
- let boxLeft = this.parentWidth / 2 - Math.ceil(left)
- let mainBox = $("#timeline-main-" + this.guid)[0];
- mainBox.style.left = boxLeft + "px";
- },
- // 设置录像背景
- setBackground(records) {
- this.recordRange = []
- if (records && records.length > 0) {
- let dayStart = this.lastBgSetDate + " 00:00:00"
- let dayEnd = this.lastBgSetDate + " 23:59:59"
- records.forEach(item => {
- if (item.strBeginTime <= dayEnd) {
- item.strBeginTime = item.strBeginTime >= dayStart ? item.strBeginTime : dayStart
- item.strEndTime = item.strEndTime <= dayEnd ? item.strEndTime : dayEnd
- let location = this.getLocationByTimeRange(item.strBeginTime, item.strEndTime)
- this.recordRange.push(location)
- }
- })
- }
- },
- // 更新录像背景
- updateBackground() {
- if (this.recordRange && this.recordRange.length > 0) {
- let records = JSON.parse(JSON.stringify(this.recordRange))
- this.recordRange = []
- for (let index = 0; index < records.length; index++) {
- let element = this.getLocationByTimeRange(records[index].strBeginTime, records[index].strEndTime)
- this.recordRange.push(element)
- }
- }
- },
- // 通过时间段获取位置
- getLocationByTimeRange(beginTime, endTime) {
- let result = {strBeginTime: beginTime, strEndTime: endTime}
- let startSecond = this.timeToSec(beginTime.split(" ")[1]);
- let left = startSecond / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
- result.left = left.toFixed(1)
- let endSecond = this.timeToSec(endTime.split(" ")[1]);
- let width = (endSecond - startSecond) / (24 * 3600 + this.intervalArr[this.intervalNum]) * this.$refs["timeline-main"].offsetWidth;
- result.width = width.toFixed(1)
- return result
- },
- // 刷新时间点
- refresh() {
- var d = new Date();
- // 初始化时间定为当前的时分
- let now = 0;
- this.timeArr = [];
- //最大时间点24点对应的秒数,也就是86400s
- let max = 86400;
- while (now < max) {
- this.timeArr.push(this.secToTime(now));
- now += this.intervalArr[this.intervalNum];
- }
- this.timeArr.push("23:59:59");
- let offsetLeft = this.$refs["timeline-main"].offsetLeft;
- this.$nextTick(() => {
- let allTimelines = document.querySelectorAll(
- ".timeline-text-" + this.guid
- );
- let offsetWidth = allTimelines[0].offsetWidth;
- let num = Math.floor((this.parentWidth / 2 - offsetLeft) / offsetWidth)
- let intervalWidth = this.parentWidth / 2 - offsetLeft - (offsetWidth * num)
- let nowSecond = this.intervalArr[this.intervalNum] * (num + intervalWidth / offsetWidth)
- this.selectTime = this.secToTime(nowSecond)
- // 更新录像背景
- this.updateBackground()
- });
- },
- // 放大
- turnUp() {
- if (this.intervalNum <= 0) {
- return;
- }
- if (this.paddingRight >= this.maxRight) {
- this.paddingRight = this.minRight;
- this.intervalNum -= 1;
- } else {
- this.paddingRight += 3;
- }
- // 刷新时间轴
- this.refresh();
- },
- // 缩小
- turnDown() {
- if (this.intervalNum >= this.intervalArr.length - 1) {
- return;
- }
- if (this.paddingRight <= this.minRight) {
- this.paddingRight = this.maxRight;
- this.intervalNum += 1;
- } else {
- this.paddingRight -= 3;
- }
- // 刷新时间轴
- this.refresh();
- },
- // 节流函数
- throttle(fn, delay) {
- let timer = null;
- return function () {
- if (timer) {
- return;
- }
- timer = setTimeout(() => {
- fn.apply(this, arguments);
- timer = null;
- }, delay);
- };
- },
- // 防抖函数
- debounce(fn, time, timer) {
- var timer = timer || null;
- return function () {
- let args = arguments;
- clearTimeout(timer);
- timer = setTimeout(() => {
- fn.call(this, args);
- }, time);
- };
- },
- },
- mounted() {
- this.parentWidth = this.$refs["timeline-" + this.guid].offsetWidth;
- this.paddingRight = this.maxRight
- var box = $("#timeline-main-" + this.guid);
- // 初始化默认是12点
- this.$nextTick(() => {
- this.positionTime("12:00:00")
- });
- // 刷新时间轴
- this.refresh();
- // 时间点右边距增加减少事件
- const upEvent = this.throttle(this.turnUp, 10);
- const downEvent = this.throttle(this.turnDown, 10);
- const that = this;
- // 鼠标滑轮事件
- var scrollFunc = function (e) {
- e = e || window.event;
- // 阻止冒泡和默认行为
- e.stopPropagation();
- e.preventDefault();
- if (e.wheelDelta) {
- //判断浏览器IE,谷歌滑轮事件
- if (e.wheelDelta > 0) {
- //当滑轮向上滚动时
- upEvent();
- }
- if (e.wheelDelta < 0) {
- //当滑轮向下滚动时
- downEvent();
- }
- } else if (e.detail) {
- //Firefox滑轮事件
- if (e.detail > 0) {
- //当滑轮向上滚动时
- upEvent();
- }
- if (e.detail < 0) {
- //当滑轮向下滚动时
- downEvent();
- }
- }
- return false;
- };
- //给页面绑定滑轮滚动事件
- if (document.addEventListener) {
- this.$refs["timeline-main"].addEventListener("DOMMouseScroll", scrollFunc, false);
- }
- //滚动滑轮触发scrollFunc方法
- document.querySelector("#timeline-main-" + this.guid).onmousewheel = scrollFunc;
-
- var body = $("body");
- var index = 0;
- var x1;
- // 按下鼠标左键
- box.mousedown(function () {
- index = 1; //鼠标按下才能触发onmousemove方法
- var x = event.clientX; //鼠标点击的坐标值,x
- var left = this.style.left;
- left = left.substr(0, left.length - 2); //去掉px
- x1 = parseInt(x - left);
- });
- // 鼠标指针在时间轴中移动
- box.mousemove(function () {
- if (index === 1) {
- let allTimelines = document.querySelectorAll(".timeline-text-" + that.guid);
- let offsetWidth = allTimelines[0].offsetWidth;
- let left = event.clientX - x1;
- if (left > that.parentWidth / 2) {
- return;
- }
- if (left < 0 && -left + that.parentWidth / 2 > offsetWidth * (allTimelines.length - 1)) {
- return;
- }
- this.style.left = left + "px";
- let num = Math.floor((that.parentWidth / 2 - left) / offsetWidth)
- let intervalWidth = that.parentWidth / 2 - left - (offsetWidth * num)
- let nowSecond = that.intervalArr[that.intervalNum] * (num + intervalWidth / offsetWidth)
- that.selectTime = that.secToTime(nowSecond)
- }
- });
- // 松开鼠标左键
- box.mouseup(function () {
- index = 0;
- });
- body.mouseup(function () {
- index = 0;
- });
- window.addEventListener("resize", (this.resizeFn = this.debounce(() => {
- this.parentWidth = this.$refs["timeline-" + this.guid].offsetWidth;
- }, 50))
- );
- },
- created() {
- this.guid = Math.ceil((1 + Math.random()) * 100000000);
- },
- deactivated() {
- window.removeEventListener("resize", this.resizeFn);
- },
- };
- </script>
-
- <style>
- .record-bg-span {
- z-index: -1;
- background: #EEBBB8;
- position: absolute;
- height: 100%;
- }
- .record-bg-div {
- width: 100%;
- position: absolute;
- height: 100%;
- top: 0;
- }
- .timeline {
- height: 26px;
- overflow-x: hidden;
- background: #eee;
- position: relative;
- width: calc(100% - 120px);
- margin-left: 120px;
- }
- .timeline-line {
- position: absolute;
- border-right: 1px solid red;
- left: 50%;
- height: 26px;
- margin: 0;
- z-index: 1;
- }
- .timeline-main {
- -moz-user-select: none;
- -khtml-user-select: none;
- user-select: none;
- position: absolute;
- left: 0;
- top: 4px;
- cursor: pointer;
- opacity: 0.9;
- }
- </style>
|