#adding content to cells in a table – how to check for clashes?

1 messages · Page 1 of 1 (latest)

fathom thicket
#

I'm working on a scheduling document that displays events for each month in a linear fashion as shown. The events are defined in a Yaml file and could potentially overlap, in which case they should "simply" go to the line below. My first attempt just increments each event on its own line, but that's needlessly sparse as many events are on different time periods and can perfectly fit on the same line.

I'm not sure how to keep track or which cells are empty – tables simply seem to produce an error when adding content to a cell already taken, but I don't know if there's a API to probe for it?
Failing that, my next idea would be to implement a "shadow table" where I keep a binary matrix of used cells and check against that, but I'm not too sure how to implement this (easily) in typst, as there's no 2D array/matrix type. I'd have to go with lists of arrays I guess. Would I be reinventing the wheel?

fathom thicket
#

I made a test document here to illustrate: https://typst.app/project/r84vKzKBgcEwgh8Tjze0YB

#let occupation-matrix(nrow, ncol) = {

let m = (true, )*nrow*ncol
m.chunks(ncol)
  
}

#set page(width: 21cm,height:auto)
#let test-cells(row,cols,matrix) = {

 let r = matrix.at(row)
 r.slice(calc.min(..cols),calc.max(..cols)+1).reduce( (x,y) => x and y)
  
}

// #let m = occupation-matrix(3,4)
// #m
// #test-cells(2, (2,3), m)

// #let m2 = m
// #(m2.at(2).at(3) = false)
// #m2
// #test-cells(2, (2,3), m2)

#let events = (
  (label:"aaaaa", start: 2, end: 3),
  (label:"bbbbb", start: 2, end: 2),
  (label:"ccccc", start: 0, end: 1),
  (label:"ddddd", start: 0, end: 0),
  (label:"eeeee", start: 1, end: 2),
)

#let dummy-content = {
  let m = occupation-matrix(3,4)
  for (i,e) in events.enumerate() {
    // check occupancy and go down if row is taken
    let y = 0
    while y < 3 {
      let test-clash = test-cells(y, (e.start,e.end), m)
    if test-clash { // update occupancy matrix
    for x in range(e.start,e.end+1){
      m.at(y).at(x) = false
    }
    break // fill those cells
    } else { // no good, go to next row
      y += 1 
    }
    } // finished iterating rows
    
    (table.cell(rect(width:100%,fill: rgb("ff112222"))[#e.label],
      x: e.start, colspan: e.end - e.start + 1, y: y),)
  }
}

#table(rows:(1cm,)*3,columns:(1fr,)*4, ..dummy-content)

fathom thicket
swift nexus
#

I think I would solve this with some algorithm without involving typst tables first. Build a datastructure that you use to compute the layout in rows. Then in the next step transfer that into a typst table.

it's like, if we are lucky an existing datastructure (here, typst table) is good for solving a particular algorithm. If it doesn't we use something else first.

#

maybe a simple algorithm could run like, sort by day events start. For each row, keep track of first free day. Insert event into first row where it fits.

fathom thicket
#

yes, that's what I mentioned above I think – creating a "matrix" to keep track of free cells and check for clashes. But that feels unnecessary since Typst already performs such checks under the hood when building a table (it will return an error if a cell clashes). I hope at some point there'll be a fuller API to get this info (unless I missed it). Here's how it goes together now: #1371385860918087730 message