Replace renderRows with per-track cells API, fill continuations in insertGap
This commit is contained in:
@@ -164,7 +164,10 @@ function render(data) {
|
|||||||
`<span><span class="status-dot"></span>QLab Connected</span>`;
|
`<span><span class="status-dot"></span>QLab Connected</span>`;
|
||||||
|
|
||||||
const timeline = document.getElementById('timeline');
|
const timeline = document.getElementById('timeline');
|
||||||
timeline.style.gridTemplateColumns = `repeat(${data.tracks.length}, 140px)`;
|
const numTracks = data.tracks.length;
|
||||||
|
const numRows = Math.max(...data.tracks.map(t => t.cells.length));
|
||||||
|
timeline.style.gridTemplateColumns = `repeat(${numTracks}, 140px)`;
|
||||||
|
|
||||||
data.tracks.forEach(track => {
|
data.tracks.forEach(track => {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'track-header';
|
el.className = 'track-header';
|
||||||
@@ -172,12 +175,13 @@ function render(data) {
|
|||||||
timeline.appendChild(el);
|
timeline.appendChild(el);
|
||||||
});
|
});
|
||||||
|
|
||||||
data.rows.forEach((row, rowIndex) => {
|
for (let r = 0; r < numRows; r++) {
|
||||||
const hasCue = row.cells.some(c => c.block_id && c.event && (data.blocks[c.block_id] || {}).type === 'cue');
|
const cells = data.tracks.map(t => t.cells[r] || {});
|
||||||
const hasSignal = !hasCue && row.cells.some(c => c.event && c.is_signal);
|
const hasCue = cells.some(c => c.block_id && c.event && (data.blocks[c.block_id] || {}).type === 'cue');
|
||||||
|
const hasSignal = !hasCue && cells.some(c => c.event && c.is_signal);
|
||||||
const rowCls = hasCue ? ' cue-row' : (hasSignal ? ' sig-row' : '');
|
const rowCls = hasCue ? ' cue-row' : (hasSignal ? ' sig-row' : '');
|
||||||
|
|
||||||
row.cells.forEach(c => {
|
cells.forEach(c => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'cell' + rowCls;
|
div.className = 'cell' + rowCls;
|
||||||
if (c.is_title) {
|
if (c.is_title) {
|
||||||
@@ -185,7 +189,7 @@ function render(data) {
|
|||||||
div.innerHTML = `<div class="block block-mid ${block.type || ''}"><div class="title">${block.name || ''}</div></div>`;
|
div.innerHTML = `<div class="block block-mid ${block.type || ''}"><div class="title">${block.name || ''}</div></div>`;
|
||||||
} else if (c.block_id) {
|
} else if (c.block_id) {
|
||||||
const block = data.blocks[c.block_id] || {};
|
const block = data.blocks[c.block_id] || {};
|
||||||
const isInfinity = rowIndex === data.rows.length - 1 && !c.is_end && !c.is_title;
|
const isInfinity = r === numRows - 1 && !c.is_end && !c.is_title;
|
||||||
let seg = 'mid';
|
let seg = 'mid';
|
||||||
if (c.is_start && c.is_end) seg = 'single';
|
if (c.is_start && c.is_end) seg = 'single';
|
||||||
else if (c.is_start) seg = 'start';
|
else if (c.is_start) seg = 'start';
|
||||||
@@ -206,7 +210,7 @@ function render(data) {
|
|||||||
}
|
}
|
||||||
timeline.appendChild(div);
|
timeline.appendChild(div);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -40,14 +40,14 @@ type TriggerTarget struct {
|
|||||||
Hook string `json:"hook"`
|
Hook string `json:"hook"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Timeline struct {
|
type TimelineTrack struct {
|
||||||
Tracks []Track `json:"tracks"`
|
Track
|
||||||
Blocks map[string]Block `json:"blocks"`
|
Cells []TimelineCell `json:"cells"`
|
||||||
Rows []TimelineRow `json:"rows"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimelineRow struct {
|
type Timeline struct {
|
||||||
Cells []TimelineCell `json:"cells"`
|
Tracks []TimelineTrack `json:"tracks"`
|
||||||
|
Blocks map[string]Block `json:"blocks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimelineCell struct {
|
type TimelineCell struct {
|
||||||
@@ -150,10 +150,14 @@ func BuildTimeline(show Show) (Timeline, error) {
|
|||||||
b.assignRows()
|
b.assignRows()
|
||||||
b.collapseEmptyRows()
|
b.collapseEmptyRows()
|
||||||
|
|
||||||
|
tracks := make([]TimelineTrack, len(b.tracks))
|
||||||
|
for i, t := range b.tracks {
|
||||||
|
tracks[i] = TimelineTrack{Track: t, Cells: b.trackCells[i]}
|
||||||
|
}
|
||||||
|
|
||||||
return Timeline{
|
return Timeline{
|
||||||
Tracks: b.tracks,
|
Tracks: tracks,
|
||||||
Blocks: b.blocks,
|
Blocks: b.blocks,
|
||||||
Rows: b.renderRows(),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,10 +344,22 @@ func (b *timelineBuilder) insertGap(track, beforeIndex int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gap := TimelineCell{IsGap: true}
|
||||||
|
for i := beforeIndex - 1; i >= 0; i-- {
|
||||||
|
c := b.trackCells[track][i]
|
||||||
|
if c.IsGap {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.BlockID != "" && !c.IsEnd {
|
||||||
|
gap.BlockID = c.BlockID
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
cells := b.trackCells[track]
|
cells := b.trackCells[track]
|
||||||
newCells := make([]TimelineCell, 0, len(cells)+1)
|
newCells := make([]TimelineCell, 0, len(cells)+1)
|
||||||
newCells = append(newCells, cells[:beforeIndex]...)
|
newCells = append(newCells, cells[:beforeIndex]...)
|
||||||
newCells = append(newCells, TimelineCell{IsGap: true})
|
newCells = append(newCells, gap)
|
||||||
newCells = append(newCells, cells[beforeIndex:]...)
|
newCells = append(newCells, cells[beforeIndex:]...)
|
||||||
b.trackCells[track] = newCells
|
b.trackCells[track] = newCells
|
||||||
|
|
||||||
@@ -435,41 +451,3 @@ func (b *timelineBuilder) collapseEmptyRows() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *timelineBuilder) renderRows() []TimelineRow {
|
|
||||||
maxLen := 0
|
|
||||||
for _, cells := range b.trackCells {
|
|
||||||
if len(cells) > maxLen {
|
|
||||||
maxLen = len(cells)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows := make([]TimelineRow, maxLen)
|
|
||||||
for r := range rows {
|
|
||||||
rows[r].Cells = make([]TimelineCell, len(b.tracks))
|
|
||||||
}
|
|
||||||
|
|
||||||
for trackIdx, cells := range b.trackCells {
|
|
||||||
activeBlock := ""
|
|
||||||
for r := 0; r < maxLen; r++ {
|
|
||||||
if r < len(cells) {
|
|
||||||
c := cells[r]
|
|
||||||
if c.IsGap {
|
|
||||||
if activeBlock != "" {
|
|
||||||
rows[r].Cells[trackIdx] = TimelineCell{BlockID: activeBlock}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rows[r].Cells[trackIdx] = c
|
|
||||||
if c.BlockID != "" && !c.IsEnd {
|
|
||||||
activeBlock = c.BlockID
|
|
||||||
} else if c.IsEnd {
|
|
||||||
activeBlock = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if activeBlock != "" {
|
|
||||||
rows[r].Cells[trackIdx] = TimelineCell{BlockID: activeBlock}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user