michaellunsford Posted December 2, 2013 Share Posted December 2, 2013 In a dynamically built table, what might be a way to identify large groups of empty cells that are clustered together? The goal is to combine them with rowspan and colspan attributes and drop an image in the empty space. There will be some guesswork involved in calculating actual area -- but the big challenge to overcome first is identifying and combining blank cells across rows. Any ideas? Quote Link to comment Share on other sites More sharing options...
Barand Posted December 2, 2013 Share Posted December 2, 2013 How is the table being built? Quote Link to comment Share on other sites More sharing options...
michaellunsford Posted December 2, 2013 Author Share Posted December 2, 2013 there's a MySQL query on the back-end and PHP loops through it all to create an array. Once the Array is built, PHP loops through it to build the table. The table is a basic events calendar by location. columns are days of the week (for only seven days), rows are locations. Quote Link to comment Share on other sites More sharing options...
jcbones Posted December 3, 2013 Share Posted December 3, 2013 What do you mean by "large"? The only way I see to do this is by looking ahead, depending on what "large" means, this could potentially create a good deal of overhead. Thus, slowing down the page. Quote Link to comment Share on other sites More sharing options...
michaellunsford Posted December 3, 2013 Author Share Posted December 3, 2013 By "large" I mean three or more empty rows and two or more empty columns clustered together in an HTML table. If all the columns in any particular location (displayed in rows) is completely empty for the entire week, it won't be displayed. So, each row has at least one column populated. The events and vacancies tend to cluster. The tough part is identifying clusters of empty cells in that HTML table (that the script is building from an array), so it can combine them using colspan and rowspan attributes. These areas will be populated with an image. Quote Link to comment Share on other sites More sharing options...
kicken Posted December 3, 2013 Share Posted December 3, 2013 Off hand I would say you'd probably want to first load all your data for the tables into an array, either multi-dimensional (row/column) or serial. Once you have that array you can loop through it checking for empty elements and handle them accordingly. Searching for consecutive empty cells would be relatively easy, when you find an empty cell just keep checking the next until you find a non-empty one. If you want to check other surrounding empty cells (above, below, diagonal) that would increase the difficulty some. If you could post some examples of the table you have and how you'd like it to appear instead that may help in devising a solution. Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted December 4, 2013 Share Posted December 4, 2013 is this image just a pattern to style the empty cells/region or is it a specific image that conveys some information, such as a picture of something? for the first case, set the cellspacing of the table to zero and use a css class to set the background-image of the empty cells to be the url of your pattern image. Quote Link to comment Share on other sites More sharing options...
Barand Posted December 4, 2013 Share Posted December 4, 2013 This might help <?php $xr = 10; $xc = 7; // // generate array of cells // X if data, ' ' if blank // $cells = array(); for ($r = 0; $r < $xr; $r++) { for ($c = 0; $c < $xc; $c++) { $cells[$r][$c] = rand(0,2)<1 ? 'X' : ' '; } } $gaps = array(); for ($r = 0; $r < $xr-1; $r++) { for ($c = 0; $c < $xc-1; $c++) { if ($cells[$r][$c]==' ') { $gs = gapsize($cells, $r, $c, $xr, $xc); if ($gs[3]>=3) { // accept 3 or more rows only $gaps[] = $gs; } } } } if (count($gaps) > 0) { rsort($gaps); vprintf("Largest suitable area is %d cells at row %d, col %d (%d rows x %d cols)<br>", $gaps[0]); } else echo "No suitable area found<br>"; // output the array echo '<table border="1" style="border-collapse:collapse">'; echo "<tr><th></th>"; for ($i=0; $i<$xc; $i++) echo "<th>$i</th>"; echo "</tr>"; for ($r = 0; $r < $xr; $r++) { echo "<tr><th>$r</th>"; echo '<td>' . join('</td><td>', $cells[$r]) . '</td>'; echo '<tr>'; } echo '</table>'; function gapsize(&$cells, $r, $c, $xr, $xc) { if (($cells[$r][$c+1]!=' ')||($cells[$r+1][$c]!=' ')||($cells[$r+1][$c+1]!=' ')) { return array (1, $r, $c, 1, 1); } $arr = array(); $ccount=0; $c1 = $c; while ($c1 < $xc) { if ($cells[$r][$c1]==' ') { $arr[]=$c1; ++$ccount; ++$c1; } else break; } $depths = array_fill_keys($arr, 1); foreach ($arr as $k=>$c2) { $r1 = $r+1; if ($cells[$r1][$c2] != ' ') { #$arr = array_slice($arr, 0, $k); $ccount = $k; } else { while ($r1 < $xr) { if ($cells[$r1][$c2]== ' ') { $depths[$c2]++; } else { break; } $r1++; } if ($k > 0 && $depths[$c2] < 3) $ccount = $k; } } $depths = array_slice($depths,0,$ccount); $arr = array_slice($arr,0,$ccount); $rcount = min($depths); return array($rcount*$ccount,$r,$c,$rcount,$ccount); } ?> Quote Link to comment Share on other sites More sharing options...
Barand Posted December 4, 2013 Share Posted December 4, 2013 OK, sprayed it with a can of "Datakill" to get rid of a couple of bugs and gave it a coat of varnish <?php $xr = 10; $xc = 7; // // generate array of cells // X if data, ' ' if blank // $cells = array(); for ($r = 0; $r < $xr; $r++) { for ($c = 0; $c < $xc; $c++) { $cells[$r][$c] = rand(0,2)<1 ? 'X' : ' '; } } $gaps = array(); for ($r = 0; $r < $xr-1; $r++) { for ($c = 0; $c < $xc-1; $c++) { if ($cells[$r][$c]==' ') { $gs = gapsize($cells, $r, $c, $xr, $xc); if ($gs[3]>=3 && $gs[4]>=2) { // accept 3+ rows x 2+ cols only $gaps[] = $gs; } } } } if (count($gaps) > 0) { rsort($gaps); vprintf("Largest suitable area is %d cells at row %d, col %d (%d rows x %d cols)<br>", $gaps[0]); } else echo "No suitable area found<br>"; // set boundary vars for output if (isset($gaps[0])) { list ($count, $row, $col, $rowcount, $colcount) = $gaps[0]; $rend = $row + $rowcount - 1; $cend = $col + $colcount - 1; } else { $row = $col = $rend = $cend = 999; $rowcount = $colcount = 0; } // output the array echo '<table border="1" style="border-collapse:collapse">'; echo "<tr><th></th>"; for ($i=0; $i<$xc; $i++) echo "<th>$i</th>"; echo "</tr>\n"; foreach ($cells as $r => $rowdata) { echo "<tr><th>$r</th>"; if ($r < $row || $r > $rend) { echo "<td>" . join('</td><td>', $rowdata) . "</td></tr>\n"; } else { foreach ($rowdata as $c => $cell) { if ($r==$row && $c==$col) { echo "<td rowspan='$rowcount' colspan='$colcount' style='background-color:#ccc'> </td>"; } else { if ($c < $col || $c > $cend) echo "<td>$cell</td>"; } } echo "</tr>\n"; } } echo '</table>'; function gapsize(&$cells, $r, $c, $xr, $xc) { if (($cells[$r][$c+1]!=' ')||($cells[$r+1][$c]!=' ')||($cells[$r+1][$c+1]!=' ')) { return array (1, $r, $c, 1, 1); } $arr = array(); $ccount=0; $c1 = $c; while ($c1 < $xc) { if ($cells[$r][$c1]==' ') { $arr[]=$c1; ++$ccount; ++$c1; } else break; } $depths = array_fill_keys($arr, 1); foreach ($arr as $k=>$c2) { $r1 = $r+1; if ($cells[$r1][$c2] != ' ') { #$arr = array_slice($arr, 0, $k); $ccount = $k; } else { while ($r1 < $xr) { if ($cells[$r1][$c2]== ' ') { $depths[$c2]++; } else { break; } $r1++; } if ($k > 0 && $depths[$c2] < 3) { $ccount = $k; break; } } } $depths = array_slice($depths,0,$ccount); $arr = array_slice($arr,0,$ccount); $rcount = min($depths); return array($rcount*$ccount,$r,$c,$rcount,$ccount); } ?> Quote Link to comment Share on other sites More sharing options...
michaellunsford Posted December 10, 2013 Author Share Posted December 10, 2013 Woah, Sen, that's just awesome! Hopefully with a few tweaks it'll find more than just the one space (if more than one exists, that is). To answer mac_gyver's question -- it's a photograph of one of the events listed in the table. I'll probably end up putting an in-line style in the spanned cell with a centered (and roughly scaled) background image so it doesn't push the table out of shape. Quote Link to comment Share on other sites More sharing options...
Barand Posted December 10, 2013 Share Posted December 10, 2013 It already finds multiple areas in the $gaps array. At the moment it sorts them and just uses the largest in $gap[0] Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.