自己寫的一款jq時間軸元件
阿新 • • 發佈:2018-12-20
效果圖
html
<!-- 時間軸 -->
<div id="timer-shaft"></div>
css
.f__clearfix{ *zoom: 1; } .f__clearfix:after{ visibility: hidden; display: block; font-size: 0; content: ""; clear: both; height: 0; } /* 時間軸 */ .m-timer-shaft{ width: 910px; height: 0; background: rgba(0,0,0,0); position: absolute; left: -84px; right: 0; bottom: 120px; margin: auto; z-index: 10; } .m-timer-shaft *{ box-sizing: border-box; } .m-timer-shaft .timer-progress{ height: 50px; width: 100%; background: rgba(16, 43, 35, 0.8); padding: 14px 15px 20px 15px; position: relative; -webkit-border-radius: 6px; border-radius: 6px; color: #d2d2d2; -webkit-box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5); box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5); } .m-timer-shaft .timer-progress .label{ width: 60px; height: 22px; line-height: 22px; text-align: center; border: 1px solid #d2d2d2; -webkit-border-radius: 4px; border-radius: 4px; font-size: 12px; position: absolute; left: 11px; bottom: 0; top: 0; margin: auto; } /* 進度容器 */ .m-timer-shaft .timer-progress .progress-wrap{ width: 800px; height: 16px; margin: 0 0 0 74px; position: relative; } .m-timer-shaft .progress-wrap .ruling{ width: 100%; height: 100%; position: absolute; top: 0; display: block; z-index: 1; } .m-timer-shaft .progress-wrap .ruling .r_short, .m-timer-shaft .progress-wrap .ruling .r_medium, .m-timer-shaft .progress-wrap .ruling .r_long{ position: absolute; top: 0; bottom: 0; left: 0; width: 0; margin: auto; border-right: 1px solid #c8c8c8; cursor: pointer; } .m-timer-shaft .progress-wrap .ruling .r_short{ height: 5px; top: -4px; border-color: #a5a5a5; } .m-timer-shaft .progress-wrap .ruling .r_medium{ height: 12px; top: -4px; } .m-timer-shaft .progress-wrap .ruling .r_long{ height: 18px; top: -3px; } .m-timer-shaft .progress-wrap .ruling-mark{ width: 100%; height: 100%; position: absolute; top: 0; display: block; cursor: pointer; z-index: 2; } .m-timer-shaft .progress-wrap .line{ height: 0; position: absolute; left: 0; right: 0; top: -2px; bottom: 0; margin: auto; border-bottom: 1px solid #c8c8c8; cursor: pointer; } .m-timer-shaft .progress-wrap .line::before, .m-timer-shaft .progress-wrap .line::after{ content: ""; display: block; width: 0; height: 18px; border-color: #c8c8c8; border-left: 1px solid; position: absolute; left: 0; top: -10px; } .m-timer-shaft .progress-wrap .line::after{ left: 100%; } /* 縮圖指標 */ .m-timer-shaft .progress-wrap .thumb-handle{ width: 2px; height: 20px; position: absolute; top: -14px; left: 0; background: #e45; -webkit-transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74); transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74); -webkit-transform: translateX(0) scaleX(0.5); transform: translateX(0) scaleX(0.5); z-index: 1; display: none; } /* 縮圖容器 */ .m-timer-shaft .progress-wrap .thumb-wrap{ width: 180px; height: 125px; position: absolute; top: -140px; left: 0; margin-left: -90px; -webkit-transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74); transition: all .05s cubic-bezier(0.71, 0.38, 0.33, 0.74); -webkit-transform: translateX(0); transform: translateX(0); background: rgba(16, 43, 35, 0.8); -webkit-border-radius: 1px; border-radius: 1px; display: none; } .m-timer-shaft .progress-wrap .thumb-wrap::after{ content: '暫無圖片'; display: block; width: 174px; height: 100px; line-height: 100px; text-align: center; background: rgba(16, 23, 39, 0.3); color: #aaa; font-size: 12px; letter-spacing: 2px; text-indent: 2px; position: absolute; top: 3px; left: 0; right: 0; margin: auto; z-index: 1; } .m-timer-shaft .progress-wrap .thumb-wrap img{ width: 174px; height: 100px; position: absolute; top: 3px; left: 0; right: 0; margin: auto; z-index: 2; } .m-timer-shaft .progress-wrap .thumb-wrap p{ height: 22px; line-height: 22px; position: absolute; top: 103px; padding: 0 10px; left: 0; right: 0; margin: auto; text-align: center; } /* 刻度名稱 */ .m-timer-shaft .progress-wrap .ruling-labels{ width: 100%; height: 100%; position: absolute; top: 16px; } .m-timer-shaft .progress-wrap .ruling-labels .la_txt{ width: 60px; height: 20px; line-height: 20px; text-align: center; font-size: 12px; position: absolute; left: 0; top: 0; -webkit-transform-origin: center top; transform-origin: center top; -webkit-transform: translate(-50%,0) scale(.85); transform: translate(-50%,0) scale(.85); } /* 指標 */ .m-timer-shaft .progress-wrap .hand{ width: 13px; height: 38px; position: absolute; top: -8px; left: 0; -webkit-transform: translate(-47.5%,0); transform: translate(-47.5%,0); background: url(../img/icon-finger_02.png) center center no-repeat; } /* 控制區 */ .m-timer-shaft .contral{ color: #f2f2f2; height: 40px; width: 188px; border-radius: 20px; margin: 0 auto; background: rgba(16, 43, 35, 0.8); margin-top: 20px; padding: 0 0 0 15px; -webkit-box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5); box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5); } .m-timer-shaft .contral .item{ width: 74px; height: 40px; float: left; padding: 8px 0; margin-right: 10px; } .m-timer-shaft .contral .txt{ line-height: 24px; font-size: 12px; letter-spacing: 1px; text-indent: 1px; display: block; float: left; -webkit-transform: translate(-2px , 2px); transform: translate(-2px , 2px); } .m-timer-shaft .contral .icon{ width: 24px; height: 24px; display: block; float: left; margin-right: 13px; background: url("../img/icon-fly.png") 0 0 no-repeat; cursor: pointer; } .m-timer-shaft .contral .icon.start{ background-position: 0 -24px; } .m-timer-shaft .contral .icon.start.active{ background-position: 0 -48px; } .m-timer-shaft .contral .icon.stop{ background-position: 0 -72px; } /* 結束時的處理 */ .m-timer-shaft.is_end{ bottom: 70px; } .m-timer-shaft.is_end .timer-progress{ display: none; } .m-timer-shaft.is_end .contral{ width: 100px; } .m-timer-shaft.is_end .contral .stop-item{ display: none; }
jq指令碼
/** * @description: 時間軸 * @author: 則丸 **/ ;(function($, window, document,undefined) { // 定義TimerShaft的建構函式 var TimerShaft = function (ele, opt) { this.$element = ele, this.defaults = { 'labels': [], // 刻度名稱列表 'rulingInterval': 5, // 刻度間隔 'runningTime': 5, // 執行一段需要的時間 'thumbBaseURL': '', // 縮圖相對路徑 'thumbImages': [], // 縮圖資源 'start': null, // 開始的回撥 'stop': null, // 停止的回撥 'passByLine': null, // 通過刻度線的回撥 'clickRuling': null, // 點選刻度尺的回撥 'isOpenClick': false // 是否啟用刻度容器點選事件 }, this.options = $.extend({}, this.defaults, opt) // 其他引數 this.label_len = this.options.labels.length this.rule_sum = this.options.rulingInterval * (this.label_len - 1) // 時間軸指標的位置 this.handLeft = 0 // 當前處於第幾個指標 this.currIndex = 0 // 指標運動的定時器 this.handMoveTimer = null } // 定義TimerShaft的方法 TimerShaft.prototype = { // 渲染方法 init: function () { var scope = this // 時間軸 var timer_progress = ` <div class="timer-progress"> <div class="label">時間視點</div> <div class="progress-wrap"> <div class="ruling"></div> <div class="ruling-mark"></div> <div class="line"></div> <div class="thumb-handle"></div> <div class="thumb-wrap"> <img/> <p></p> </div> <div class="ruling-labels"></div> <div class="hand"></div> </div> </div> ` // 控制區域 var timer_contral = ` <div class="contral f__clearfix"> <div class="item"> <i class="icon start"></i> <span class="txt">開始</span> </div> <div class="item stop-item"> <i class="icon stop"></i> <span class="txt">結束</span> </div> </div> ` // 主要的html繪製 this.$element.addClass('m-timer-shaft is_end').append(timer_progress + timer_contral) // 時間軸樣式 調整 this.setTimerShaftStyle(); // 刻度渲染 this.ruleRender() var rulingHandle = function (ev) { // 是否啟用 if (!scope.options.isOpenClick) return ev || (ev = window.event) var dom_width = scope.$element.find('.progress-wrap').width() var w_block = dom_width / scope.rule_sum var ruling_offsetLeft = $(this).offset().left var ev_left = ev.clientX scope.handLeft = ev_left - ruling_offsetLeft scope.currIndex = parseInt(scope.handLeft / w_block) scope.options.clickRuling && scope.clickRuling(scope.options.currIndex) // 重啟 | 啟動 scope.restart() $(this).siblings(".hand").css('left', scope.handLeft + 'px'); } // 縮圖 刻度容器觸控事件 var thumbHandleHover = function (ev) { ev || (ev = window.event) var dom_width = scope.$element.find('.progress-wrap').width() var w_block = dom_width / scope.rule_sum var ruling_offsetLeft = $(this).offset().left var ev_left = ev.clientX var offset_left = ev_left - ruling_offsetLeft var the_index = Math.floor(offset_left / (w_block * scope.options.rulingInterval)) var thumb_handle = scope.$element.find(".thumb-handle") var thumb_wrap = scope.$element.find(".thumb-wrap") thumb_handle.css({ 'WebkitTransform': `translateX(${offset_left}px) scaleX(0.5)`, 'transform': `translateX(${offset_left}px) scaleX(0.5)` }).show() var attr_index = thumb_wrap.find('img').attr('data-index') if(attr_index&&attr_index!=the_index) { // 當圖片存在時 if (scope.options.thumbImages[the_index]) { thumb_wrap.find('img').attr('src' ,scope.options.thumbBaseURL + scope.options.thumbImages[the_index]).show() } else { thumb_wrap.find('img').hide() } } thumb_wrap.find('img').attr('data-index', the_index) thumb_wrap.find('p').html(scope.options.labels[the_index]) thumb_wrap.css({ 'WebkitTransform': `translateX(${offset_left}px)`, 'transform': `translateX(${offset_left}px)` }).show() } // 縮圖 刻度容器 離開觸控事件 var thumbHandleLeave = function (ev) { var thumb_handle = scope.$element.find(".thumb-handle") var thumb_wrap = scope.$element.find(".thumb-wrap") ev || (ev = window.event) thumb_handle.hide() thumb_wrap.hide() } this.$element.find(".ruling-mark").click(rulingHandle) this.$element.find(".ruling-mark").mousemove(thumbHandleHover) this.$element.find(".ruling-mark").mouseleave(thumbHandleLeave) return this }, // 渲染時間軸刻度 ruleRender: function () { if (!this.options.labels) return this.$element var $timer_progress = this.$element.find('.timer-progress') var dom_width = $timer_progress.find('.progress-wrap').width() var w_block = dom_width / this.rule_sum var append_dom = '' var long_len = 0 var labels_dom = `<div class="la_txt" style="left: 0px;">${this.options.labels[0]}</div>` for (var i = 0; i< this.rule_sum - 1 ;i++) { if ((i + 1) % this.options.rulingInterval === 0) { if (long_len % 2 === 0) { append_dom += `<div class='r_medium' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>` } else { append_dom += `<div class='r_long' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>` } labels_dom += `<div class="la_txt" style="left: ${(i+1)*w_block}px;">${this.options.labels[long_len+1]}</div>` long_len += 1 } else { append_dom += `<div class='r_short' point-num='${i+1}' style="left: ${(i+1)*w_block}px;"></div>` } } labels_dom += `<div class="la_txt" style="left: ${(this.rule_sum)*w_block}px;">${this.options.labels[this.label_len - 1]}</div>` $timer_progress.find(".ruling").html('').append(append_dom) $timer_progress.find(".ruling-labels").html('').append(labels_dom) return this.$element }, // 時間軸樣式 調整 setTimerShaftStyle: function () { var bgColor = "rgba(16, 43, 35, 0.8)" var wrap_width = $(window).width() - 653; wrap_width = wrap_width > 1000 ? 1000 : wrap_width wrap_width = wrap_width < 380 ? 380 : wrap_width this.$element.css({ 'width': wrap_width + 'px' }); this.$element.find('.progress-wrap').css('width', (wrap_width - 110) + 'px'); // 顏色設定 this.$element.find('.timer-progress').css('backgroundColor', bgColor); this.$element.find('.contral').css('backgroundColor', bgColor); }, // 時間軸動畫 timelineAnimate: function () { var dom_width = this.$element.find('.progress-wrap').width() var w_block = dom_width / this.rule_sum var fps_distance = (dom_width / (this.label_len - 1)) / this.options.runningTime / (1000 / 60) this.handLeft += fps_distance this.$element.find(".hand").css('left', this.handLeft + 'px'); var the_index = parseInt(this.handLeft / w_block) if (the_index != this.currIndex) { this.currIndex = the_index this.options.passByLine && this.options.passByLine(this.currIndex) } if (this.handLeft>=dom_width) { this.close() } }, // 開始 begin: function () { var scope = this this.handMoveTimer = setInterval(function(){ scope.timelineAnimate() }, 1000 / 60); this.options.start && this.options.start(this) }, // 終止 close: function () { this.handLeft = 0 var dom_width = this.$element.find('.progress-wrap').width() this.$element.find(".hand").css('left', dom_width + 'px'); this.currIndex = this.options.rulingInterval * (this.label_len - 1) clearInterval(this.handMoveTimer) this.options.stop && this.options.stop(this) }, // 暫停 pause: function () { clearInterval(this.handMoveTimer) }, // 重啟 restart: function () { this.pause() this.begin() }, // 重置 reset: function () { this.handLeft = 0 this.$element.find(".hand").css('left', this.handLeft + 'px'); this.currIndex = 0 this.$element.find(".contral .start").removeClass('active').siblings('.txt').text('繼續'); clearInterval(this.handMoveTimer) } } // 在外掛中使用TimerShaft物件 $.fn.timerShaft = function (options) { // 建立Beautifier的實體 var timerShaft = new TimerShaft(this, options); // 呼叫渲染方法 timerShaft.init() var start_btn = timerShaft.$element.find(".contral .start"); var stop_btn = timerShaft.$element.find(".contral .stop"); // 啟動時間軸 start_btn.on("click", function(){ timerShaft.$element.hasClass('is_end') && timerShaft.$element.removeClass('is_end') var is_pause = $(this).hasClass('active') if (!is_pause) { $(this).addClass('active').siblings('.txt').text('暫停'); timerShaft.begin() } else { $(this).removeClass('active').siblings('.txt').text('繼續'); timerShaft.pause() } }) // 終止時間軸 stop_btn.on("click", function(){ timerShaft.$element.hasClass('is_end') || timerShaft.$element.addClass('is_end') start_btn.removeClass('active').siblings('.txt').text('開始'); timerShaft.close() }) // 瀏覽器視窗變化時, 時間軸樣式調整 $(window).resize(function(){ timerShaft.setTimerShaftStyle(); // 時間軸重新渲染 timerShaft.reset(); timerShaft.ruleRender(); }) return timerShaft; } })(jQuery, window, document);