1

更新された質問:

次の図に示すように、イベントをタイムラインに表示したいと考えています。

欲しかった結果

イベント データ項目には「開始時間」と「長さ」の 2 つの属性があるため、データは次のようなテーブルとして想像できます。

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 の場合と同じ問題があります。

  • 明示的なネスティング情報は利用できませんが、暗黙的なネスティング情報は開始時間と長さによって提供されます。
  • イベントは開始時刻の昇順で並べ替えられます。

したがって、イベントを表示する方法は 1 つだけです。


現在、私はこのようにしようとしています: x 位置は で設定されてmargin-leftいますが、他の属性も問題ありません。s は、divx 値によって並べ替えられます。

<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;
}

これが現在の結果です (この場合、イベント名は数字ですが、任意の文字列にすることができます):

結果

各行に 1 つだけあるdivため、後続の各行divはその前の行の下にあります。

要素の y 位置を計算することなく、純粋な CSS でこれを行う方法はありますか?

サンプル コードは、http: //jsfiddle.net/hiddenbit/PvBjt/から入手できます。

4

5 に答える 5

0

要件が非常にあいまいであっても、私の2つのアイデアをリングに投げ込みます。

最初の試み

margin-topほとんどの要素に a を追加しました。レベル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 */
}

2 回目の試行

要素の実際の構造によっては、よりクリーンな 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

これは、他の回答の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 に答える
0

divCSS だけで sをレイアウトすることはできないようです。そのため、JavaScriptを使用して次のソリューションを作成しました。

データ リストが走査され、divが動的に追加されます。絶対配置が使用されます。

  • 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 に答える