gpt4 book ai didi

javascript - 创建像SO开发人员故事这样的垂直时间轴

转载 作者:技术小花猫 更新时间:2023-10-29 12:06:54 25 4
gpt4 key购买 nike

我目前正在尝试制作垂直时间轴(就像在stackoverflow开发人员故事中一样)。

要求如下:

  • 时间线不应只左右改变项目,也不应该在相对侧(not like thisthis)上留出空间
  • 如果需要,左侧和右侧项目应填满剩余空间(like here,不幸的是,一旦项目的内容变长,就不会保留项目的顺序)
  • 项目的顺序应与所提供的DOM结构中的顺序相同,因此在时间线
  • 中应排在最前面的项目


    因此,在第一步中,我只想测试如何将项目相应地对齐到左侧或右侧。

    这是我目前拥有的:

    .timeline {
    width: 100%;
    }

    .timeline-item {
    box-sizing: border-box;
    width: 50%;
    position: relative;
    float: left;
    clear: left;
    padding-left: 20px;
    margin: 1px 0 1px;
    background: tomato;
    }

    .timeline-item.inverse {
    float: right;
    clear: right;
    background: grey;
    }


    /* Just used to show the middle point alignment */

    .timeline-item::after {
    content: '';
    height: 2px;
    width: 10px;
    background: DarkGrey;
    position: absolute;
    top: 50%;
    right: 0;
    }

    .timeline-item.inverse::after {
    left: 0;
    background: DarkRed;
    }
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript" ></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" type="text/javascript" ></script>

    <div class="timeline">
    <div class="timeline-item">
    <p>
    1 This is some sample text (multiline)
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    <br>This is some sample text
    </p>
    </div>
    <div class="timeline-item inverse">
    <p>
    2 This is some sample text
    </p>
    </div>
    <div class="timeline-item inverse">
    <p>
    3 This is some sample text
    </p>
    </div>
    <div class="timeline-item">
    <p>
    4 This is some sample text
    </p>
    </div>
    </div>


    这样可以很好地创建项目的简单明了的对齐方式。

    我需要的下一步是保持项目的顺序。

    正如您在小提琴中看到的那样,这些项目只是粘在一起以漂浮顶部。不幸的是,我对如何做到这一点一无所知。

    我以为普通CSS是不可能的,因此可能需要JavaScript来重新放置项目,但我不知道如何操作,如何测量等(我不是JavaScript专家。)。

    有没有人已经做到这一点并可以分享他的经验?还是什至没有我找不到的图书馆?

    已经谢谢你了!

    最佳答案

    目前无法使用普通CSS。但是,可以使用JavaScript来完成。
    随意跳到底部进行演示,或继续阅读以获取详细说明。

    A screenshot of the demo.

    方法。 我建议的解决方案如下。
    •时间线上的事件绝对位于时间线容器内。
    •JavaScript确定事件在时间轴上的位置,最后确定时间轴容器的高度。使用内联样式和一个类指示事件是在时间线的左侧还是右侧设置的。例如,该类可用于添加箭头。
    •CSS确定事件和时间线的大小和外观。

    要求。 问题提出以下要求。
    R1时间线不应只左右改变事件。
    R2如果需要,左右事件应填充剩余空间。
    R3。项目的顺序应与提供的DOM结构中的顺序相同。

    定位算法。 事件按照在DOM(R3)中出现的顺序在时间轴上从上到下定位。该算法跟踪每边的最后一个事件的底部,例如BL和BR。事件的位置越靠下,这些数字就越高,因为它们记录了与时间轴顶部的偏移量。

    假设我们要定位事件E。我们选择将其定位在底部最小的一侧。因此,由min(BL,BR)决定。这是在演示中的功能min中实现的。然后,我们将E尽可能靠近时间轴的顶部放置,同时仍将其置于有效位置。有效位置是这样的位置,即没有其他事件重叠,并且事件的中心(该事件与时间轴的连接点)必须位于时间轴上的前一个点之后。设E'为与E相对的最后一个事件。设P为与E相同侧的最后一个事件。

    测试以下三个位置就足够了。
    1.将E的顶部与E'的底部对齐。这始终是有效位置,但对于R2而言不是很好。
    2.将E的中心尽可能地对准E'的中心。这对于R2更好,但是当E的顶部现在与P重叠(E的顶部小于P的底部)时,这不是有效位置。
    3.将E的顶部尽可能地对准P的底部。这对R2最好,但是当E的中心现在位于E'的中心之前时,这不是有效位置。

    该算法仅按给定的顺序测试这些位置,并在当前测试的位置有效时覆盖E的位置。这样,将选择最佳的有效位置。

    样式,详细信息和备注。 我添加了一些CSS标记来说明时间轴可以做什么。此标记和JavaScript代码应完全跨浏览器兼容。我确实没有使用ES6功能来实现最大程度的兼容性,但 Array.from 除外,该文件仍然具有良好的支持,并且在需要时可以在链接页面上为Internet Explorer提供polyfill。我自己对代码进行了最新版本的Firefox和Chrome测试。

    该代码并未针对性能进行优化,但是由于该算法以线性时间运行,因此即使时间轴中有许多事件,运行该算法也不会出现问题。该演示会重新计算每个resize event上的布局,您可能希望在实时应用程序中对其进行限制。

    在下面的演示中,您将看到有一个参数minSpace。这是一个以像素为单位的空间,它留在时间轴上的两个连续点之间以及时间轴同一侧的两个事件之间。演示对此参数使用默认值10。

    演示。 我创建了一个JSFiddle。如果愿意,还可以在此处将其作为摘要运行。我建议您调整预览窗口的大小,以便可以看到时间线布局的更新方式。

    // wrap in anonymous function to not pollute global namespace
    (function() {

    // find the minimium element in an array, and the index of it
    function min(arr) {
    var ind = -1, min = false, i;
    for (i = 0; i < arr.length; ++i) {
    if (min === false || arr[i] < min) {
    ind = i;
    min = arr[i];
    }
    }
    return {
    index: ind,
    value: min
    };
    }

    // position events within a single timeline container
    function updateTimeline(timeline, minSpace = 10) {
    var events = Array.from(timeline.querySelectorAll('.event')),
    tops = [0, 0],
    bottoms = [0, 0],
    minTops = [0, 0];
    // determine height of container, upper bound
    timeline.style.height = events.reduce(function(sum, event) {
    return sum + event.offsetHeight;
    }, 0) + 'px';

    // position events in timeline
    events.forEach(function(event) {
    // find highest point to put event at
    // first put it with its top aligned to the lowest bottom - this will
    // always yield a good solution, we check better ones later
    var h = event.offsetHeight,
    y = min(bottoms),
    x = (y.index === 0 ? 0 : 50),
    b = y.value + h,
    m = (tops[1 - y.index] + bottoms[1 - y.index]) / 2;
    event.className = 'event';
    event.classList.add('event--' + (y.index === 0 ? 'left' : 'right'));
    // try to squeeze element up as high as possible
    // first try to put midpoint of new event just below the midpoint of
    // the last placed event on the other side
    if (m + minSpace - h / 2 > minTops[y.index]) {
    y.value = m + minSpace - h / 2;
    b = y.value + h;
    }
    // it would be even better if the top of the new event could move
    // all the way up - this can be done if its midpoint is below the
    // midpoint of the last event on the other side
    if (minTops[y.index] + h / 2 > m + minSpace) {
    y.value = minTops[y.index];
    b = y.value + h;
    }

    // update tops and bottoms for current event
    tops[y.index] = Math.ceil(y.value);
    bottoms[y.index] = Math.ceil(b + minSpace);
    minTops[y.index] = bottoms[y.index];

    // update tops and bottoms for other side, as applicable
    if (y.value + (h / 2) + minSpace > bottoms[1 - y.index]) {
    tops[1 - y.index] = bottoms[1 - y.index];
    minTops[1 - y.index] = bottoms[1 - y.index];
    }
    bottoms[1 - y.index] = Math.ceil(Math.max(
    bottoms[1 - y.index],
    y.value + (h / 2) + minSpace
    ));

    // put event at correct position
    event.style.top = y.value + 'px';
    event.style.left = x + '%';
    });

    // set actual height of container
    timeline.style.height = (Math.max.apply(null, bottoms) - minSpace) + 'px';
    }

    // position events within all timeline containers on the page
    function updateAllTimelines(minSpace = 10) {
    Array.from(document.querySelectorAll('.timeline'))
    .forEach(function(timeline) {
    updateTimeline(timeline, minSpace);
    });
    }

    // initialize timeline by calling above functions
    var space = 10;
    updateAllTimelines(space);
    window.addEventListener('resize', function() {
    updateAllTimelines(space);
    });

    }());
    /* line in center */
    .timeline {
    position: relative;
    width: 100%;
    }

    .timeline:before {
    content: " ";
    display: block;
    position: absolute;
    top: 0;
    left: calc(50% - 2px);
    width: 4px;
    height: 100%;
    background: red;
    }

    /* events */
    .event {
    position: absolute;
    top: 0;
    left: 0;
    box-sizing: border-box;
    width: 50%;
    height: auto;
    padding: 0 20px 0 0;
    }
    .event--right {
    /* Move padding to other side.
    * It is important that the padding does not change, because
    * changing the height of an element (which padding can do)
    * while layouting is not handled by the JavaScript. */
    padding: 0 0 0 20px;
    }

    /* discs on timeline */
    .event:after {
    content: "";
    display: block;
    position: absolute;
    top: calc(50% - 5px);
    width: 0;
    height: 0;
    border-style: solid;
    }
    .event--left:after {
    right: 0;
    border-width: 10px 0 10px 20px;
    border-color: transparent transparent transparent #de2d26;
    }
    .event--right:after {
    left: 0;
    border-width: 10px 20px 10px 0;
    border-color: transparent #de2d26 transparent transparent;
    }

    /* event styling */
    .event__body {
    padding: 20px;
    background: #de2d26;
    color: rgba(255, 255, 255, 0.9);
    }
    <div class="timeline">
    <div class="event">
    <div class="event__body">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius sodales purus, id gravida ipsum accumsan quis. Donec ultrices orci quis ex consequat mollis. Etiam in gravida enim. Etiam efficitur lorem id turpis auctor gravida. Ut condimentum dolor nibh, in hendrerit leo egestas at.
    </div>
    </div>
    <div class="event">
    <div class="event__body">
    Nam magna felis, malesuada vitae elementum sit amet, tempus sed eros. Etiam ullamcorper elementum viverra. Morbi dictum metus id nibh congue, at lacinia felis iaculis. Etiam pretium augue in erat lobortis viverra. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse facilisis, velit vel placerat faucibus, massa est eleifend turpis, ac tempor dui turpis at mi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
    </div>
    </div>
    <div class="event">
    <div class="event__body">
    Mauris malesuada arcu sed lacus tristique, a eleifend sem egestas. Pellentesque at malesuada nisi.
    </div>
    </div>
    <div class="event">
    <div class="event__body">
    Nam et purus at elit vulputate molestie ac non eros. Proin mattis ligula velit, ut semper eros venenatis a. Vestibulum sagittis consectetur diam, molestie dapibus sem viverra a. Fusce felis augue, mollis id massa molestie, sagittis rutrum risus. In vel molestie elit, eget fringilla ante. Sed et elit blandit, tincidunt leo non, vehicula mi. Aenean tempus tincidunt eros vel tincidunt. Integer orci orci, gravida sit amet elit nec, luctus condimentum est.
    </div>
    </div>
    <div class="event">
    <div class="event__body">
    Pellentesque sodales ultrices sem, eget convallis ante condimentum id. Fusce ac turpis ac ex tincidunt malesuada a ac est.
    </div>
    </div>
    </div>


    最后。 如果您遇到任何问题,请告诉我。

    关于javascript - 创建像SO开发人员故事这样的垂直时间轴,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42919642/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com