1

更新的问题:

我想在时间轴中显示事件,如下图所示:

想要的结果

事件数据项有两个属性:“开始时间”和“长度”,因此可以将数据想象为如下所示的表格:

event name | start | length
-----------+-------+-------
1          |   0   | 200 
1.1        |  30   | 100 
1.1.1      |  40   |  50 
1.2        | 140   |  50 
2          | 205   | 100 
2.1        | 220   |  20 
2.2        | 250   |  20 
2.3        | 280   |  20 
...        | ...   | ...

数据有一些特点:

  • 事件名称可以是任意的(这里的数字只是为了说明)
  • 在另一个事件的范围内开始和结束的事件是这些事件的子事件。
    → 在上表中,“1.1”将是“1”的子事件。
  • 儿童可以有儿童活动。
  • 事件永远不会以下列方式重叠……</p>

    +---------+                 +---------+
    |    A    |                 |    C    |
    +---------+                 +---------+
        +---------+   or   +---------+ 
        |    B    |        |    D    | 
        +---------+        +---------+ 
    

    ...因为 B 将是 A 的孩子,但它必须在 A 结束之前结束。C 从 D 开始,因此 D 将是 C 的父级(并且必须显示在 C 上方),但是与 A 和 B 存在相同的问题。

  • 没有可用的显式嵌套信息,但隐式嵌套信息由开始时间和长度提供。
  • 事件按开始时间升序排序。

因此,事件的显示方式只有一种。


目前我正在尝试这样做:x 位置设置为margin-left,但任何其他属性也可以。divs 按它们的 x 值排序:

<div class="container">
    <div class="item" style="margin-left:0; width: 200px;">
        1
    </div>
    <div class="item" style="margin-left:30px; width: 100px;">
        1.1
    </div>
    <div class="item" style="margin-left:40px; width: 50px;">
        1.1.1
    </div>
    <div class="item" style="margin-left:140px; width: 50px;">
        1.2
    </div>
    <div class="item" style="margin-left:205px; width: 100px;">
        2
    </div>
    <div class="item" style="margin-left:220px; width: 20px;">
        2.1
    </div>
    <div class="item" style="margin-left:250px; width: 20px;">
        2.2
    </div>
    <div class="item" style="margin-left:280px; width: 20px;">
        2.3
    </div>
</div>
.container {
    padding: 0.5rem 0 1.5rem 0;
    background-color: #EEE;
    border: 1px solid #888;
    overflow-x: auto;
}

.item {
    height: 2rem;
    margin-bottom: -1rem;
    font-size: 60%; font-family: sans-serif;
    background-color: #BBB;
    border: 1pt solid #EEE;
    overflow: hidden;
}

这是当前结果(在这种情况下,事件名称是数字,但它们可以是任意字符串):

结果

每行恰好有一个div,因此每个后续div都低于其前任。

任何想法如何用纯 CSS 做到这一点而不必计算元素的 y 位置?

示例代码可在此处获得:http: //jsfiddle.net/hiddenbit/PvBjt/

4

5 回答 5

0

您可以在每个元素上使用负上边距来修复垂直偏移。

http://jsfiddle.net/PvBjt/1/

margin-top:-##px;
于 2013-05-22T14:50:51.413 回答
0

我已将您更改.itemposition: absolute;并给出了子项目的类以及像素top值:

.item {
  position: absolute;
}
.sub-item {
   top:35px;
}
.sub-sub-item {
  top: 55px;
}

更新的小提琴

于 2013-05-22T14:57:17.490 回答
0

即使要求非常模糊,也将我的 2 个想法投入到环中。

第一次尝试

margin-top在大多数元素中添加了一个;级别x.x获取margin-top:20px和级别x.x.x获取margin-top:40px。与@YaMo 类似的方法。

演示

HTML

<div class="container">
    <div class="item" style="margin-left:0; width: 200px;">1</div>
    <div class="item" style="margin-left:30px; margin-top:20px; width: 100px;">1.1</div>
    <div class="item" style="margin-left:40px; margin-top:40px; width: 50px;">1.1.1</div>
    <div class="item" style="margin-left:140px; margin-top:20px; width: 50px;">1.2</div>
    <div class="item" style="margin-left:205px; width: 100px;">2</div>
    <div class="item" style="margin-left:220px; margin-top:20px; width: 20px;">2.1</div>
    <div class="item" style="margin-left:250px; margin-top:20px; width: 20px;">2.2</div>
    <div class="item" style="margin-left:280px; margin-top:20px; width: 20px;">2.3</div>
</div>

CSS

.item {
    position:absolute; /* just add to existing properties */
}

第二次尝试

元素的一些实际结构允许更简洁的 HTML 和更通用的 CSS。我无法提出通用规则的唯一部分是 item 的宽度1.2。这当然取决于能够改变 HTML 结构。

演示

HTML

<div class="container">
    <ul>
        <li class="item">1
            <ul>
                <li class="item">1.1
                    <ul>
                        <li class="item">1.1.1</li>
                    </ul>
                </li>
                <li class="item">1.2</li>
            </ul>
        </li>
        <li class="item">2
            <ul>
                <li class="item">2.1</li>
                <li class="item">2.2</li>
                <li class="item">2.3</li>       
            </ul>
        </li>
    </ul>
</div>

CSS

.container {
    padding: 0.5rem 0 1.5rem 0;
    background-color: #EEE;
    border: 1px solid #888;
}

.item {
    height:2rem;
    background-color: #BBB;
    border: 1pt solid #EEE;
    display:inline-block;
    vertical-align:top;
    min-width:20px;
}

li:only-child {
    min-width:50px;
}

ul {
    margin:0;
    padding:0;
    list-style-type:none;
}

.container > ul > li {
    display:inline-block;
    vertical-align:top;
    font-size: 60%; font-family: sans-serif;
}

ul li:first-child {
    margin-left:20px;
}

ul li:last-child {
    margin-right:10px;
}
于 2013-05-22T16:05:32.970 回答
0

似乎不可能div仅使用 CSS 来布局 s。因此,我使用 JavaScript 制作了以下解决方案。

遍历数据列表并div动态添加 s。使用绝对定位:

  • left设置为开始时间
  • 堆栈数据结构用于top跟踪隐式父级

HTML:

<div id="container"></div>

JavaScript:

var data = [
    ["1",      0, 200 ],
    ["1.1",   30, 100 ],
    ["1.1.1", 40,  50 ],
    ["1.2",  140,  50 ],
    ["2",    205, 100 ],
    ["2.1",  220,  20 ],
    ["2.2",  250,  20 ],
    ["2.3",  280,  20 ]
];

var endStack = [];
var maxStackHeight = 0;
var container = document.getElementById("container");

data.forEach(function(row) {
    // create div
    var div = document.createElement("div");
    div.className = "item";
    div.appendChild(document.createTextNode(row[0]));
    var x = row[1]; var w = row[2];
    div.style.left = x.toString() + "px";
    div.style.width = w.toString() + "px";

    // get level of div
    for (var i = endStack.length-1; i >= 0; i--) {
        if (x > endStack[i]) {  
            // current event starts after current top-of-stack ends → remove
            endStack.pop();  
        } else {
            // current event is child of current top-of-stack event
            break;
        }
    }

    // set y position based on stack height
    div.style.top = (endStack.length).toString() + "rem";

    // append to container
    container.appendChild(div);

    // push end of added event to stack
    endStack.push(x + w);

    // set maximum stack height 
    maxStackHeight = Math.max(maxStackHeight, endStack.length);
});

// set container height based on maximum stack height 
container.style.height = (maxStackHeight + 1.1).toString() + "rem";

CSS:

#container {
    background-color: #EEE;
    border: 0.1rem solid #888;
    overflow-x: auto;
    position: relative;
}

.item {
    position: absolute;
    height: 2rem;
    font-size: 60%; font-family: sans-serif;
    background-color: #BBB;
    border: 0.1rem solid #EEE;
    overflow: hidden;
}

演示

于 2013-05-23T07:14:47.863 回答
0

这是使用我的其他答案中的 CSS和 JavaScript 来创建事件结构的替代解决方案<ul>

演示

JavaScript

window.onload=function(){
  var events = [
    { name: '1', start: 0, length: 300},
    { name: '1.1', start: 30, length: 100},
    { name: '1.1.1', start: 40, length: 50},
    { name: '1.2', start: 140, length: 50},
    { name: '1.3', start: 200, length: 50},
    { name: '2', start: 305, length: 100},
    { name: '2.1', start: 320, length: 20},
    { name: '2.2', start: 350, length: 20},
    { name: '2.3', start: 380, length: 20},
    { name: '3', start: 410, length: 50}
  ];

  var html = [];
  var containerEventEnd = [];
  var prevEventEnd = Infinity;

  for (var i = 0; i < events.length; i++) {
    var e = events[i];
    var eventEnd = e.start + e.length;

    if (e.start > containerEventEnd[1]) {
      containerEventEnd.shift();
      html.push('</ul>');
    }

    if (eventEnd > containerEventEnd[0]) {
      containerEventEnd.shift();
      containerEventEnd.unshift(eventEnd);
    }

    if (e.start > prevEventEnd) {
      html.push('</li>');
    } else {
      html.push('<ul>');
      containerEventEnd.unshift(eventEnd);
    }

    html.push('<li class="item">' + e.name); // every item is just an <li>
    prevEventEnd = eventEnd;
  }

  document.getElementById('container').innerHTML = html.join('\n');
};

CSS

#container {
    padding: 0.5rem 0 1.5rem 0;
    background-color: #EEE;
    border: 1px solid #888;
}

.item {
    height:2rem;
    background-color: #BBB;
    border: 1pt solid #EEE;
    display:inline-block;
    vertical-align:top;
    min-width:20px;
}

li:only-child {
    min-width:50px;
}

ul {
    margin:0;
    padding:0;
    list-style-type:none;
}

#container > ul > li {
    display:inline-block;
    vertical-align:top;
    font-size: 60%; font-family: sans-serif;
}

ul li:first-child {
    margin-left:20px;
}

ul li:last-child {
    margin-right:10px;
}

HTML

<div id="container"></div>
于 2013-05-23T09:51:33.827 回答