Добавьте несколько colspans, которые выстраиваются в HTML

Я создаю планировщик календаря, где я надеюсь добавить несколько задач в одну строку сотрудника. Всякий раз, когда я пытаюсь добавить несколько задач на один и тот же промежуток времени, промежутки больше не выстраиваются в линию. Вот пример того, как это выглядит сейчас: Calendar as of now. Какова была бы лучшая практика добавления задач в столбцы того же дня, если бы такая задача, как "Slaughter them", была аналогичной?

Скрипт HTML:

<script>
                  var sysDate = new Date();
                  var sysDay = new Date();
                  var sysMonth = new Date();
                  var dayCount = sysDay.getDay();
                  var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
                  let employee;
                  let typeofKey;
                  let empArry = [];
                  let x = 1;
                  let y = 0;
                  let trInc= 0;
                  var drawTable = '<table id = wholeTable>';
                  drawTable += "<thead>";
                  drawTable += "<tr>";
                  drawTable += "<th style='color:white;'>Employee Name<\/th>";
                  let today = new Date();
                  let dd = today.getDate();
                  let mm = today.getMonth()+1; //January is 0!
                  let mmN = mm;
                  let yyyy = today.getFullYear();
                  let oneWeekAhead = new Date();
                  let nextWeek = (today.getDate()+10) + 10;
                                    /* If next week falls into the next month, print correctly */
                  if (nextWeek > 30 && (mmN == 9 || mmN == 4 || mmN == 6 || mmN == 11)) {
                    mmN++;
                    nextWeek -= 30;
                  }
                  else if (nextWeek > 31 && (mmN == 1 || mmN == 3 || mmN == 5 || mmN == 7 || mmN == 8 || mmN == 10 || mmN == 12)) {
                    mmN++;
                    nextWeek -= 31;
                  }
                  else if (nextWeek > 28 && mmN == 2) {
                    mmN++;
                    nextWeek -= 28;
                  }
                                    /* Formatting of the dates at the top of the table */
                  if(dd < 10) {
                    dd = '0'+ dd;
                  }
                  if(nextWeek < 10) {
                    nextWeek = '0' + nextWeek;
                  }
                  if(mmN < 10) {
                      mmN = '0' + mmN
                  }
                  if(mm < 10) {
                    mm = '0' + mm;
                  }
                  let edate = yyyy + mmN + nextWeek;
                  /* Finds the logged earliest and latest dates */
                  let startDate1  = yyyy.toString() +  mm.toString() + dd.toString();
                  let startDate = parseInt(startDate1);
                  let endDate = parseInt(edate);
                  let startDateN = 20180501;
                  let endDateN = 20180531;
                                    /* Change the strings of dates to ints for calculation of start and end date of the table */
                  if( localStorage.length > 0){
                  for (var key in localStorage) {
                    typeofKey = (typeof localStorage[key]);
                    if (typeofKey == 'string' || typeofKey instanceof String ){
                      emp1 = JSON.parse(localStorage.getItem(key));
                      if ("Task" in emp1) {
                        for (let i = 0; i < emp1.Task.length; i++) {
                          startDateN = parseInt(emp1.Task[i]['Task Start Date'].substr(0,4) + emp1.Task[i]['Task Start Date'].substr(5,2) + emp1.Task[i]['Task Start Date'].substr(8,2));
                          endDateN = parseInt(emp1.Task[i]['Task End Date'].substr(0,4) + emp1.Task[i]['Task End Date'].substr(5,2) + emp1.Task[i]['Task End Date'].substr(8,2));
                          if(endDateN > endDate) {
                            endDate = endDateN;
                          }
                          if(startDateN < startDate) {
                            startDate = startDateN;
                          }
                        }
                      }
                    }
                  }
                }
                  let numStr = null;
                  let numStrDay = null;
                  let finalDay = null;
                  let finalDayF = null;
                  let colCount = 0;
                                    /* Correctly print the months and days at the top of the table */
                  for (let i = startDate; i <= endDate +1; i++) {
                    numStr = (i.toString()).substr(4,2);
                    numStrDay = (i.toString()).substr(6,2);
                    if(numStr == '09' || numStr == '04' || numStr == '06' || numStr == '11') {
                      if(numStrDay == '31') {
                        i += 69;
                      }
                      else {
                        finalDay = i.toString()
                        finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
                        drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
                        colCount++;
                      }
                    }
                    else if(numStr == '01' || numStr == '03' || numStr == '05' || numStr == '07' || numStr == '08' || numStr == '10' || numStr == '12') {
                      if(numStrDay == '32') {
                        i += 68;
                      }
                      else {
                        finalDay = i.toString()
                        finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
                        drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
                        colCount++;
                      }
                    }
                    else if(numStr == '02') {
                      if(numStrDay == '29') {
                        i += 71;
                      }
                      else {
                        finalDay = i.toString()
                        finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
                        drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
                        colCount++;
                      }
                    }
                    else {
                      finalDay = i.toString()
                      finalDayF = (finalDay.substr(0,4)) + "-" + (finalDay.substr(4,2)) + "-" + (finalDay.substr(6,2));
                      drawTable += "<th class = days id = days" + x + '-' + y + ">" + finalDayF + "</th>";
                      colCount++;
                    }
                    x++;
                  }
                  drawTable += "</tr>";
                  drawTable += "</thead>";
                  drawTable += '<tbody class="dragscroll">';
                  //drawTable += "<tr id =" + trInc + ">";
                  //trInc++;
                  //counters for the employee and date rows/col
                  x=0;
                  y=1;
                  // counter for the main table
                  let z =1;
                  for (var key in localStorage) {
                    typeofKey = (typeof localStorage[key]);
                    //cols of the employee names
                    if(typeofKey == 'string' || typeofKey instanceof String ){
                                            drawTable += "<tr id =" + trInc + ">";
                          trInc++;
                      employee = JSON.parse(localStorage.getItem(key));
                      drawTable += "<td class = employ id =emp" + x + '-' + y + ">" + employee['Employee Name'] + "</td>";
                      // rows and cols of the main table and date
                      for (let j = 0; j < colCount; j++) {
                        drawTable += "<td class =" + z + '-' + y + "></td>";
                        z++;
                      }
                      // set z to one to start the main tables x at 1 for off by one error
                      z=1;
                      //reset x for each row
                      x=0;
                    drawTable += '</tr>';
                    y++;
                  }
                }
               drawTable += '<tr>';
               var noRows = 14 - localStorage.length;
                for(; noRows >= 0; noRows--){
                  drawTable += "<td class = employ id =emp" + x + '-' + y + ">" + "" + "</td>";
                  // rows and cols of the main table and date
                  for (let j = 0; j < colCount; j++) {
                    drawTable += "<td class =" + z + '-' + y + "></td>";
                    z++;
                  }
                  // set z to one to start the main tables x at 1 for off by one error
                  z=1;
                  //reset x for each row
                  x=0;
                drawTable += '</tr>';
                y++;
                }
                drawTable += "</tbody>";
                drawTable += "</table>";
                document.write(drawTable);
                        </script>

CSS:

table {
  /* border: 0.0625em solid black; */
  table-layout: fixed;
  position: relative;
  width: auto;
  overflow: hidden;
  border-collapse: collapse;
  box-shadow: 0 0 20px rgba(0,0,0,0.1);
}

html, body{
  height: 100%;
  width: 100%;
  background: linear-gradient(45deg, #e1e1e1, #f6f6f6);
}

/*thead*/
thead {
  position: relative;
  display: block; /*seperates the header from the body allowing it to be positioned*/
  width: 1535px;
  overflow: visible;
  /* border: 1px solid black; */
}

td, th {
    padding: 0.75em 1.5em;
    text-align: left;
}

thead th {
  min-width: 140px;
  max-width: 140px;
  height: 35px;
  text-align: center;
}

thead th:nth-child(1) { /*first cell in the header*/
    position: relative;
    display: float;
    min-width: 140px;
    background-color: #202020;
}

/*tbody*/
tbody {
  position: relative;
  display: block; /*seperates the tbody from the header*/
  width: 1535px;
  height: 475px;
  overflow: scroll;
}

tbody td {
  background-color: white;
  min-width: 140px;
  max-width: 140px;
  border: 2px solid #474747;
  white-space: nowrap;
}

tbody tr td:nth-child(1) {  /*the first cell in each tr*/
  position: relative;
  /*display: block; seperates the first column from the tbody*/
  height: 40px;
  min-width: 140px;
  max-width: 140px;
}

.dragscroll {
  overflow-y: hidden;
  margin-right: 0;
  height: 600px;
}

.days {
    background-color: #31bc86;
    color: white;
    text-align: center;
}

.employ {
        background-color: #2ea879;
        color: white;
        text-align: center;
}

#taskDiv {
  position: absolute;
  border: 2px solid black;
}

#days, #emp{
background-color: #071833;
color: white;
}

::-webkit-scrollbar {
    width: 20px;
}

/* Track */
::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px black;

}

/* Handle */
::-webkit-scrollbar-thumb {
    background: #071833;

}

/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
    background: #1caf8f
}

JS:

function getRandomColor() {
  var letters = '0123456789ABCDEF';
  var color = '#';
  for (var i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}

$(document).ready(function(){
  let typeofKey;
  let empArry = [];
  let employee;
  let myTable = document.getElementById('wholeTable');
  let colFill = false;
  let color = null;
        //cols of the employee names
  for (var i = 0; i < localStorage.length; i++){
      empArry.push(localStorage.key(i))
  }
  // loop through the local storage and pull the data
  for(let j = 0; j < empArry.length; j++){
    color = getRandomColor();
    employee = JSON.parse(localStorage.getItem(empArry[j]));
    // If employee has any task
    if("Task" in employee){
      // while employee has task in his array
      for(let taskIndex = 0; taskIndex < employee.Task.length; taskIndex++){
         for(let k = 1; k < myTable.rows[0].cells.length; k++) {
           if(myTable.rows[0].cells[k].innerHTML == employee.Task[taskIndex]["Task Start Date"]) {
             colFill = true;
           }
           if(colFill == true) {
             myTable.rows[j+1].cells[k].innerHTML += '<div style="background-color:' + color + '">' + employee.Task[taskIndex]["Task Name"] + '</br></div>';
           }
           if(myTable.rows[0].cells[k].innerHTML == employee.Task[taskIndex]["Task End Date"]) {
             colFill = false;
           }
         }
       }
     }
   }
});

JSFiddle: https://jsfiddle.net/py5gzw0b/1/#&togetherjs=eM8xgAd5eV

Ответы

Ответ 2

Если вам нужно, чтобы каждый элемент находился на собственной строке [вместе со всеми идентичными задачами] и идеально выровнен, вам нужно создать строку 1 и вставить только задачи Slaughter, а затем создать строку 2, вставив только задачи Cry, Тогда это обеспечило бы, чтобы все они правильно совпадали друг с другом, хотя в результате это заняло бы больше места.

Ответ 3

Другим решением, помимо создания строки для каждой задачи, было бы использование jQuery для поиска "максимальной вершины задачи" и установки всех экземпляров в этом верхнем. Поскольку они занимают одно и то же пространство, это должно быть выполнимым и более гибким, НО вы находитесь за какое-то удовольствие от css-позиционирования.

Чтобы быть более конкретным, вы должны:

1/Добавить уникальный идентификатор для каждой задачи: <div id_task="1" style=...

2/Петля на каждом экземпляре, чтобы найти максимальное верхнее значение:

maxTop=0;
$('[id_task=1]').each(function(){
  newTop=$(this).position().top;
  if(newTop>maxTop)maxTop=newTop;
});

3/Используйте maxTop чтобы установить все id_task=1 на один и тот же верхний id_task=1, возможно, также установите эти div соответственно: $('[id_task=1]').css({'top':maxTop,'position':'relative');

4/Наслаждайтесь тонкой настройкой этого, чтобы закрыть свою желаемую цель, это займет некоторое время ^^

Я сделал код быстро, как пример, там нет никакой гарантии.

Ответ 4

Взгляните на это:

var cols = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
var employees = [
  {
    Name: 'Jason',
    Task:[
      {'Task Start Date':'Mon','Task End Date':'Thu','Task Name':'Do nothing'},
      {'Task Start Date':'Thu','Task End Date':'Fri','Task Name':'Do a bit'},
      {'Task Start Date':'Sat','Task End Date':'Sun','Task Name':'Do everything'}
    ]
  },
  {
    Name: 'Timmy',
    Task:[
      {'Task Start Date':'Mon','Task End Date':'Sun','Task Name':'On vacation'},
      {'Task Start Date':'Sat','Task End Date':'Sun','Task Name':'Still on vacation'},
    ]
  }
]

function RowCompound(employee,columns){
	var tasks = employee.Task
	var spans = []
  var max_rows = 1
  var rowmap = []
  var rows = []
  
  function calcSpans(){
  	for(var i=0;i<tasks.length;i++){
      var cspan = null
      for(var u=0;u<columns.length;u++){
        if(tasks[i]['Task Start Date']==columns[u]){
          cspan = {row:0,start:u,task:tasks[i]}
        }
        if(cspan && tasks[i]['Task End Date']==columns[u]){
          cspan.end = u
          spans.push(cspan)
          cspan = null
        }
      }
      if(cspan){
        cspan.end = columns.length-1
        spans.push(cspan)
      }
    }
  }
  
  function solveConflicts(){
  	var conflict = true
    while(conflict){
      conflict = false
      for(var i=0;i<spans.length;i++){
        for(var u=i+1;u<spans.length;u++){
          if(spans[i].row!=spans[u].row) continue
          if(spans[i].start>spans[u].end || spans[i].end<spans[u].start) continue
          conflict = true
          max_rows = Math.max(max_rows,++spans[u].row + 1)
        }
      }
    }
  }
  
  function createRowMap(){
  	for(var u=0;u<max_rows;u++){
      var row = []
      for(var i=0;i<columns.length;i++){
        var empty = true
        for(var k=0;k<spans.length;k++){
          if(spans[k].row!=u) continue
          if(i==spans[k].start){
            empty = false
            var span = spans[k].end-spans[k].start+1
            row.push({task:spans[k].task,colspan:span,rowspan:1})
            i += span-1
            break
          }
        }
        if(empty)
          row.push({task:null,colspan:1,rowspan:1})
      }
      rowmap.push(row)
    }
  }
  
  function buildDom(){
    for(var i=0;i<rowmap.length;i++){
      var row = document.createElement('tr')
      for(var u=0;u<rowmap[i].length;u++){
        if(rowmap[i][u].rowspan==0) continue
        var cell = document.createElement('td')
        cell.colSpan = rowmap[i][u].colspan
        cell.rowSpan = rowmap[i][u].rowspan
        if(rowmap[i][u].task){
          cell.innerHTML = rowmap[i][u].task['Task Name']
          cell.className = 'busy'
        }
        row.appendChild(cell)
      }
      rows.push(row)
    }
    
    var head = document.createElement('td')
    head.rowSpan = max_rows
    head.innerHTML = employee.Name
    rows[0].prepend(head)
  }
  
  calcSpans()
  solveConflicts()
  createRowMap()
  buildDom()
  
  return rows
}


// example use
employees.forEach(function (emp){
	var result_rows = RowCompound(emp,cols)
  for(var i in result_rows){
    document.getElementById('table').appendChild(result_rows[i])
  }
})
table{
  width: 100%;
  border-collapse: collapse;
}

table td{
  border: solid 1px #ccc;
  width: 50px;
}
table td.busy{
  background-color: dodgerblue;
  color: white;
}
<table id="table">
  <thead>
    <th>Employee</th>
    <th>Mon</th>
    <th>Tue</th>
    <th>Wed</th>
    <th>Thu</th>
    <th>Fri</th>
    <th>Sat</th>
    <th>Sun</th>
  </thead>
</table>

Ответ 5

Это скорее концептуальный ответ/идея, но я думаю, что вы могли бы использовать библиотеку макетов JavaScript в изотопах с режимом "вертикального" макета:

https://isotope.metafizzy.co/layout-modes.html

Вы можете отключить все виды анимаций, поэтому в этом смысле это будет ярлык для "позиционирования css", который @Nomis упоминает в ответе выше. Там также может быть интересна библиотека https://masonry.desandro.com того же человека.