水平时间轴固定距离并以移动设备为中心

时间:2017-04-13 06:33:18

标签: javascript jquery css timeline

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

我的问题是,我没有真正的约会(DD / MM / YYYY),但只有1998-2002或2009年的年份。所以有一个问题,我正在努力修复,最终会像这样:

enter image description here

所以我的目标是:

  1. 设置元素之间的固定距离
  2. 让它与多年一起工作
  3. 在宽度小于768像素的设备上,确保显示单个元素并显示在中心
  4. 这是我对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;
        }
    }
    

    你们知道如何调整它,因为我几个小时都没有成功地挣扎。非常感谢你的帮助!

2 个答案:

答案 0 :(得分:2)

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

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, "");
    }
});

答案 1 :(得分:0)

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

  

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

     

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

source:: www.codyhouse.org

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

var timelines = $('.cd-horizontal-timeline'),
    eventsMinDistance = 60;

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

这将创建一个名为timelines的变量,并将其设置为类.cd-hor ...并将最小距离设置为60px。将此值更改为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');
    }
}

我可能错了,但是这里是计算距离的部分,最后的距离是N * min +&#39; px&#39;。 min我相信是60,距离范数是5天等的计算。如果你移除距离规范应用程序中断,所以你不能只添加min +&#39; px&#39;这是因为你删除了原始距离。

所有距离均从第一个时间轴计算得出。这就是应用程序破解的原因。需要找到代码来告诉哪个来自哪个

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

这将距离设置为索引的第一个元素,然后设置循环[i]中的每个timelineDates。

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

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