【问题标题】:horizontal timeline fixed distance and centered on mobile devices水平时间线固定距离并以移动设备为中心
【发布时间】:2017-04-13 06:33:17
【问题描述】:

我正在尝试达到这样的水平时间线: https://codepen.io/ritz078/pen/LGRWjE

我的问题是,我没有真正的日期 (DD/MM/YYYY),但只有 1998-2002 年或 2009 年这样的年份。所以有一个问题,我正在努力解决,结果是这样:

所以我的目标是:

  1. 设置元素之间的固定距离
  2. 让它在几年内发挥作用
  3. 在宽度小于 768 像素的设备上确保显示单个元素并显示在中心

这是我对 3. 的解决方案,但其他的,我无法解决:

if ($(window).width() < 768 {
    eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
}

(timelines.length > 0) && initTimeline(timelines);

$(window).resize(function(){
    if ($(window).width() < 768 {
    eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
    } else{
        eventsMinDistance = 155;
    }
}

你们知道如何调整它,因为我几个小时以来一直在挣扎,没有任何成功。非常感谢您的帮助!

【问题讨论】:

    标签: javascript jquery css timeline


    【解决方案1】:

    您的代码的第一部分工作正常,但语法有问题,我修复并使用它,还添加了一些更改以在每个日期之间完成所需的固定宽度量。 实际上这很容易,当您调试并且您确切地知道开发人员想要做什么时。 这是我写的代码:

    jQuery(document).ready(function($){
        var timelines = $('.cd-horizontal-timeline'),
            eventsRelativeDistance = false;
        if ($(window).width() < 768) {
            eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
        }else{
            var eventsMinDistance = 100;
        }
    
        (timelines.length > 0) && initTimeline(timelines);
    
        $(window).resize( function(){
            if ($(window).width() < 768) {
                eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
            } else{
                eventsMinDistance = 100;
            }
        });
    
        function initTimeline(timelines) {
            timelines.each(function(){
                var timeline = $(this),
                    timelineComponents = {};
                //cache timeline components
                timelineComponents['timelineWrapper'] = timeline.find('.events-wrapper');
                timelineComponents['eventsWrapper'] = timelineComponents['timelineWrapper'].children('.events');
                timelineComponents['fillingLine'] = timelineComponents['eventsWrapper'].children('.filling-line');
                timelineComponents['timelineEvents'] = timelineComponents['eventsWrapper'].find('a');
                timelineComponents['timelineDates'] = parseDate(timelineComponents['timelineEvents']);
                timelineComponents['eventsMinLapse'] = minLapse(timelineComponents['timelineDates']);
                timelineComponents['timelineNavigation'] = timeline.find('.cd-timeline-navigation');
                timelineComponents['eventsContent'] = timeline.children('.events-content');
                if(!eventsRelativeDistance){
                    // Set up space to store the distance in pixels.
                    timelineComponents['distanceInPx'] = [];
                }
    
                //assign a left postion to the single events along the timeline
                setDatePosition(timelineComponents, eventsMinDistance, eventsRelativeDistance);
                //assign a width to the timeline
                var timelineTotWidth = setTimelineWidth(timelineComponents, eventsMinDistance, eventsRelativeDistance);
                //the timeline has been initialize - show it
                timeline.addClass('loaded');
    
                //detect click on the next arrow
                timelineComponents['timelineNavigation'].on('click', '.next', function(event){
                    event.preventDefault();
                    updateSlide(timelineComponents, timelineTotWidth, 'next');
                });
                //detect click on the prev arrow
                timelineComponents['timelineNavigation'].on('click', '.prev', function(event){
                    event.preventDefault();
                    updateSlide(timelineComponents, timelineTotWidth, 'prev');
                });
                //detect click on the a single gallery - show new gallery content
                timelineComponents['eventsWrapper'].on('click', 'a', function(event){
                    event.preventDefault();
                    timelineComponents['timelineEvents'].removeClass('selected');
                    $(this).addClass('selected');
                    updateOlderEvents($(this));
                    updateFilling($(this), timelineComponents['fillingLine'], timelineTotWidth);
                    updateVisibleContent($(this), timelineComponents['eventsContent']);
                });
    
                //on swipe, show next/prev gallery content
                timelineComponents['eventsContent'].on('swipeleft', function(){
                    var mq = checkMQ();
                    ( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'next');
                });
                timelineComponents['eventsContent'].on('swiperight', function(){
                    var mq = checkMQ();
                    ( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'prev');
                });
    
                //keyboard navigation
                $(document).keyup(function(event){
                    if(event.which=='37' && elementInViewport(timeline.get(0)) ) {
                        showNewContent(timelineComponents, timelineTotWidth, 'prev');
                    } else if( event.which=='39' && elementInViewport(timeline.get(0))) {
                        showNewContent(timelineComponents, timelineTotWidth, 'next');
                    }
                });
            });
        }
    
        function updateSlide(timelineComponents, timelineTotWidth, string) {
            //retrieve translateX value of timelineComponents['eventsWrapper']
            var translateValue = getTranslateValue(timelineComponents['eventsWrapper']),
                wrapperWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', ''));
            //translate the timeline to the left('next')/right('prev')
            (string == 'next')
                ? translateTimeline(timelineComponents, translateValue - wrapperWidth + eventsMinDistance, wrapperWidth - timelineTotWidth)
                : translateTimeline(timelineComponents, translateValue + wrapperWidth - eventsMinDistance);
        }
    
        function showNewContent(timelineComponents, timelineTotWidth, string) {
            //go from one gallery to the next/previous one
            var visibleContent =  timelineComponents['eventsContent'].find('.selected'),
                newContent = ( string == 'next' ) ? visibleContent.next() : visibleContent.prev();
    
            if ( newContent.length > 0 ) { //if there's a next/prev gallery - show it
                var selectedDate = timelineComponents['eventsWrapper'].find('.selected'),
                    newEvent = ( string == 'next' ) ? selectedDate.parent('li').next('li').children('a') : selectedDate.parent('li').prev('li').children('a');
    
                updateFilling(newEvent, timelineComponents['fillingLine'], timelineTotWidth);
                updateVisibleContent(newEvent, timelineComponents['eventsContent']);
                newEvent.addClass('selected');
                selectedDate.removeClass('selected');
                updateOlderEvents(newEvent);
                updateTimelinePosition(string, newEvent, timelineComponents);
            }
        }
    
        function updateTimelinePosition(string, event, timelineComponents) {
            //translate timeline to the left/right according to the position of the selected gallery
            var eventStyle = window.getComputedStyle(event.get(0), null),
                eventLeft = Number(eventStyle.getPropertyValue("left").replace('px', '')),
                timelineWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')),
                timelineTotWidth = Number(timelineComponents['eventsWrapper'].css('width').replace('px', ''));
            var timelineTranslate = getTranslateValue(timelineComponents['eventsWrapper']);
    
            if( (string == 'next' && eventLeft > timelineWidth - timelineTranslate) || (string == 'prev' && eventLeft < - timelineTranslate) ) {
                translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotWidth);
            }
        }
    
        function translateTimeline(timelineComponents, value, totWidth) {
            var eventsWrapper = timelineComponents['eventsWrapper'].get(0);
            value = (value > 0) ? 0 : value; //only negative translate value
            value = ( !(typeof totWidth === 'undefined') &&  value < totWidth ) ? totWidth : value; //do not translate more than timeline width
            setTransformValue(eventsWrapper, 'translateX', value+'px');
            //update navigation arrows visibility
            (value == 0 ) ? timelineComponents['timelineNavigation'].find('.prev').addClass('inactive') : timelineComponents['timelineNavigation'].find('.prev').removeClass('inactive');
            (value == totWidth ) ? timelineComponents['timelineNavigation'].find('.next').addClass('inactive') : timelineComponents['timelineNavigation'].find('.next').removeClass('inactive');
        }
    
        function updateFilling(selectedEvent, filling, totWidth) {
            //change .filling-line length according to the selected gallery
            var eventStyle = window.getComputedStyle(selectedEvent.get(0), null),
                eventLeft = eventStyle.getPropertyValue("left"),
                eventWidth = eventStyle.getPropertyValue("width");
            eventLeft = Number(eventLeft.replace('px', '')) + Number(eventWidth.replace('px', ''))/2;
            var scaleValue = eventLeft/totWidth;
            setTransformValue(filling.get(0), 'scaleX', scaleValue);
        }
    
        function setDatePosition(timelineComponents, min, relativeDistance) {
            var distance,
                distanceNorm = 0,
                distancesInPx =[];
            for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
                if (relativeDistance){
                    distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]);
                    distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
                }else{
                    distance = 5;
                    distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2 + distanceNorm;
                    // Save am array of sizes to track the distance in pixels from the left.
                    timelineComponents['distanceInPx'].push(distanceNorm*min);
                }
                timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
            }
        }
    
        function setTimelineWidth(timelineComponents, width, relativeDistance) {
            var timeSpan = 0, timeSpanNorm, totalWidth;
            if(relativeDistance){
                // If relative Time Distance daydiff caclulates the first date and the last one.
                timeSpan = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][timelineComponents['timelineDates'].length-1]);
                timeSpanNorm = timeSpan/timelineComponents['eventsMinLapse'];
                    timeSpanNorm = Math.round(timeSpanNorm) + 4;
                    totalWidth = timeSpanNorm*width;
            }else{
                // However if no relative Distance we obtain the amount of distance in pixels from the last position of the array which is the farthest element on the array.
                totalWidth = timelineComponents['distanceInPx'][timelineComponents['distanceInPx'].length-1];
            }
            timelineComponents['eventsWrapper'].css('width', totalWidth+'px');
            updateFilling(timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents['fillingLine'], totalWidth);
            updateTimelinePosition('next', timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents);
    
            return totalWidth;
        }
    
        function updateVisibleContent(event, eventsContent) {
            var eventDate = event.data('date'),
                visibleContent = eventsContent.find('.selected'),
                selectedContent = eventsContent.find('[data-date="'+ eventDate +'"]'),
                selectedContentHeight = selectedContent.height();
    
            if (selectedContent.index() > visibleContent.index()) {
                var classEnetering = 'selected enter-right',
                    classLeaving = 'leave-left';
            } else {
                var classEnetering = 'selected enter-left',
                    classLeaving = 'leave-right';
            }
    
            selectedContent.attr('class', classEnetering);
            visibleContent.attr('class', classLeaving).one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){
                visibleContent.removeClass('leave-right leave-left');
                selectedContent.removeClass('enter-left enter-right');
            });
            eventsContent.css('height', selectedContentHeight+'px');
        }
    
        function updateOlderEvents(event) {
            event.parent('li').prevAll('li').children('a').addClass('older-gallery').end().end().nextAll('li').children('a').removeClass('older-gallery');
        }
    
        function getTranslateValue(timeline) {
            var timelineStyle = window.getComputedStyle(timeline.get(0), null),
                timelineTranslate = timelineStyle.getPropertyValue("-webkit-transform") ||
                    timelineStyle.getPropertyValue("-moz-transform") ||
                    timelineStyle.getPropertyValue("-ms-transform") ||
                    timelineStyle.getPropertyValue("-o-transform") ||
                    timelineStyle.getPropertyValue("transform");
    
            if( timelineTranslate.indexOf('(') >=0 ) {
                var timelineTranslate = timelineTranslate.split('(')[1];
                timelineTranslate = timelineTranslate.split(')')[0];
                timelineTranslate = timelineTranslate.split(',');
                var translateValue = timelineTranslate[4];
            } else {
                var translateValue = 0;
            }
    
            return Number(translateValue);
        }
    
        function setTransformValue(element, property, value) {
            element.style["-webkit-transform"] = property+"("+value+")";
            element.style["-moz-transform"] = property+"("+value+")";
            element.style["-ms-transform"] = property+"("+value+")";
            element.style["-o-transform"] = property+"("+value+")";
            element.style["transform"] = property+"("+value+")";
        }
    
        //based on http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript
        function parseDate(events) {
            var dateArrays = [];
            events.each(function(){
                var singleDate = $(this),
                    dateComp = singleDate.data('date').split('T');
                if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided
                    var dayComp = dateComp[0].split('/'),
                        timeComp = dateComp[1].split(':');
                } else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide
                    var dayComp = ["2000", "0", "0"],
                        timeComp = dateComp[0].split(':');
                } else { //only DD/MM/YEAR
                    var dayComp = dateComp[0].split('/'),
                        timeComp = ["0", "0"];
                }
                var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]);
                dateArrays.push(newDate);
            });
            return dateArrays;
        }
    
        function daydiff(first, second) {
            return Math.round((second-first));
        }
    
        function minLapse(dates) {
            //determine the minimum distance among events
            var dateDistances = [];
            for (i = 1; i < dates.length; i++) {
                var distance = daydiff(dates[i-1], dates[i]);
                dateDistances.push(distance);
            }
            return Math.min.apply(null, dateDistances);
        }
    
        /*
            How to tell if a DOM element is visible in the current viewport?
            http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        */
        function elementInViewport(el) {
            var top = el.offsetTop;
            var left = el.offsetLeft;
            var width = el.offsetWidth;
            var height = el.offsetHeight;
    
            while(el.offsetParent) {
                el = el.offsetParent;
                top += el.offsetTop;
                left += el.offsetLeft;
            }
    
            return (
                top < (window.pageYOffset + window.innerHeight) &&
                left < (window.pageXOffset + window.innerWidth) &&
                (top + height) > window.pageYOffset &&
                (left + width) > window.pageXOffset
            );
        }
    
        function checkMQ() {
            //check if mobile or desktop device
            return window.getComputedStyle(document.querySelector('.cd-horizontal-timeline'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
        }
    });
    

    【讨论】:

      【解决方案2】:

      你有没有让这个工作?遇到过同样的问题。如果我将默认距离从 60 更改为 1,则两者之间的差距不够,整个时间线都会中断。文章中描述的距离计算如下

      首先,在 main.js 文件中,我们使用 eventsMinDistance 变量设置两个连续日期之间的最小距离;在我们的例子中,我们设置 eventsMinDistance = 60(所以最小距离为 60px)。然后我们评估一个日期和下一个日期之间的所有差异;为此,我们使用添加到每个日期的 data-date 属性。然后使用最小差异作为参考来评估两个连续日期之间的距离。

      例如,假设发现的最小差异是 5 天;这意味着在时间线上,相隔 5 天的两个日期之间的距离将为 60 像素,而相隔 10 天的两个事件之间的距离将为 120 像素。

      source:: www.codyhouse.org

      从我读到的最小距离在这里:~

      var timelines = $('.cd-horizontal-timeline'),
          eventsMinDistance = 60;
      
      (timelines.length > 0) && initTimeline(timelines);
      

      这将创建一个名为时间线的变量并将其设置为 .cd-hor... 类并将最小距离设置为 60 像素。将此更改为 1 会中断应用程序,因为时间之间的距离太小。

      function setDatePosition(timelineComponents, min) {
          for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
              var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
                  distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
              timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
          }
      }
      

      我可能错了,但这里是计算距离和最后一个 distanceNorm*min+'px' 的部分。 min 我相信是 60,距离标准是 5 天等的计算。如果你删除距离标准,应用程序会中断,所以你不能只添加 min+'px',这是因为你删除了原始距离。

      所有距离都是从第一条时间线开始计算的。这就是应用程序崩溃的原因。需要找到告诉哪个来计算哪个是

      var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
                  distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
      

      这会将距离设置为索引的第一个元素,然后将距离设置为循环 [i] 中的每个时间线日期。

      我已经学习了好几天了,但得出的结论是,本教程很好,但它不是一个库,应该用作从头开始编写自己的参考,这就是我现在正在做的。

      如果你曾经管理过它,请更新,到目前为止我设法操纵日期以获得相等的间距,但如果你插入太多它会中断,这是不好的,因此重写!

      【讨论】:

      • 如果您有问题,并且此处的答案无助于解决问题,请使用该功能。如果相关,您可以随时链接回这个问题。您已在“答案”部分发布此内容,但它没有回答上述问题。
      • 我知道它没有回答,但也许原始发帖人找到了答案,所以我问了。它不适合评论。没有一个人回答他的问题,他们为什么要回答我的问题,而这个社区似乎只是挑剔每个试图学习的人。有趣的是,一个超过一年的话题没有得到帮助,但我的评论确实赶走了那些互联网战士。真是太棒了,这么棒的社区有人指出错误而不是提供帮助。
      猜你喜欢
      • 2017-09-13
      • 1970-01-01
      • 2019-06-09
      • 1970-01-01
      • 2017-08-05
      • 1970-01-01
      • 2014-03-17
      • 2020-10-07
      • 1970-01-01
      相关资源
      最近更新 更多