brooksh Posted March 12, 2012 Share Posted March 12, 2012 I'm trying to create a sitemap page. With Main categories and then sub categories. Some have no subcategories and some have a lot. I want them evenly distributed into each column. I can't seem to find a script. Can someone help? I want it to look similar to this http://www.walmart.com/cp/All-Departments/121828 Here is a small portion of the categories: <ul class="dirlist"> <li><a class="s1" href="Accessories.htm"><b>A</b>ccessories</a></li> <ul class="subcats"> <li><a href="Belts.htm">Belts</a></li> <li><a href="Gloves-and-Mittens.htm">Gloves & Mittens</a></li> </ul> <li><a class="s1" href="Activewear.htm"><b>A</b>ctivewear</a></li> <li><a class="s1" href="Handbags-and-Luggage.htm"><b>H</b>andbags & Luggage</a></li> <ul class="subcats"> <li><a href="Backpacks.htm">Backpacks</a></li> <li><a href="Briefcases.htm">Briefcases</a></li> <li><a href="Computer-Bags.htm">Computer Bags</a></li> </ul> </ul> Quote Link to comment Share on other sites More sharing options...
btherl Posted March 12, 2012 Share Posted March 12, 2012 It's a messy problem in general. If I was doing it I would start by deciding the number of columns, then developing a way to measure the vertical size of each category. That would be something like "title + 1 (the gap) + number of subcats". Then it's a matter of adding categories to each column (which could be represented by adding them into an array) until they reach approximately 1/5 of the total size of all categories. Then start adding to the next column, and so on. Quote Link to comment Share on other sites More sharing options...
l0gic Posted March 12, 2012 Share Posted March 12, 2012 In the past I've used a various sitemap generating software. Not sure how dynamic you want this to be, but it may be worth jumping on Google and doing a search for a Sitemap Generator? Quote Link to comment Share on other sites More sharing options...
xyph Posted March 12, 2012 Share Posted March 12, 2012 Here's an exhaustive article on accomplishing the task using mark-up alone. http://www.alistapart.com/articles/multicolumnlists/ Personally, I would probably go the way btherl suggested. Quote Link to comment Share on other sites More sharing options...
brooksh Posted March 13, 2012 Author Share Posted March 13, 2012 Here's an exhaustive article on accomplishing the task using mark-up alone. http://www.alistapart.com/articles/multicolumnlists/ Personally, I would probably go the way btherl suggested. This works for categories. It doesn't work for categories with subcategories. this is why I'm having such a hard time. I've even looked at hotscripts.com to find something without any luck. Quote Link to comment Share on other sites More sharing options...
darkfreaks Posted March 13, 2012 Share Posted March 13, 2012 http://codeassembly.com/How-to-display-inifinit-depth-expandable-categories-using-php-and-javascript/ Quote Link to comment Share on other sites More sharing options...
xyph Posted March 13, 2012 Share Posted March 13, 2012 Here's what I ended up with. To get absolutely ideal results, you'll have to mess with $value['cat'] and $value['subcat']. Messing with how the average is calculated is optional as well, as it's used to determine if we should move on to the next column or try to squeak one last category in. <style type="text/css"> #sitemap td { border: 1px solid black; vertical-align: top; font: 10px sans-serif; } #sitemap h3,ul { margin: 0; } #sitemap h3{ margin-top: 10px; } </style> <?php $data = array(); // Generate some random data for( $i=0,$imax=rand(15,30); $i < $imax; $i++ ) { $data[$i] = array('Category '.($i+1),array()); for( $j=0,$jmax=rand(0,10); $j < $jmax; $j++ ) $data[$i][1][$j] = 'Subcategory '.($j+1); } // Some parameters for our script. $columns = 4; // Number of columns $value['cat'] = 3; // A 'size' value given to categories $value['subcat'] = 2; // A 'size' value given to subcategories $value['total'] = 0; // Will contain the total size value of all the categories and subcategories $value['average'] = 0; // Will contain the average size value of each catgories and it's subs $value['percolumn'] = 0; // The size value each columb should be close to // Get a sum of all categories and sub-categories. foreach( $data as $category ) $value['total'] += $value['cat'] + count($category[1]) * $value['subcat']; $value['average'] = floor( $value['total'] / count($data) ); $value['percolumn'] = floor( $value['total'] / $columns ); echo '<table id="sitemap"><tr><td>'; $column_value = 0; // Will hold the total value of the current column $column_current = 1; // Will hold the current column number foreach( $data as $category ) { // Grab the value of the category about to be displayed $cat_value = $value['cat'] + count($category[1]) * $value['subcat']; // Check if category is too big for column, unless it's the last column if( ($cat_value+$column_value) > ($value['percolumn']+$value['average']) && $column_current < $columns ) { // For debugging echo 'Column value total: '.$column_value; // Start a new column echo '</td><td>'; // Reset the total column value $column_value = 0; // Increment the current column $column_current++; } // Output category echo '<h3>'.$category[0].'</h3>'; // Verify category isn't empty if( !empty($category[1]) ) { // Output subcategories echo '<ul>'; foreach( $category[1] as $subcategory ) echo '<li>'.$subcategory.'</li>'; echo '</ul>'; } // Add category's value to the column's value $column_value += $cat_value; } // For debugging echo 'Column value total: '.$column_value; // End the table echo '</td></tr></table>'; // More debugging print_r( $value ); ?> It'd say without any changes, it works quite well. If someone wants to steam-line this a little, we could have a really cool snippet. There are some unnecessary variables used, I know. I just wanted to isolate as much logic as possible for ease of understanding. EDIT - If you're finding the last column doesn't have enough content, change the average calculation to something like this. $value['average'] = floor( $value['total'] / count($data) * 2/3 ); The greater the variation in category size, the greater the chance you'll end up with unideal results. Quote Link to comment Share on other sites More sharing options...
xyph Posted March 13, 2012 Share Posted March 13, 2012 More thinking: If this was something you could cache, you could run a loop that totals each column, and tests a bunch of possibilities for the most 'ideal' distribution. Hmmm. Back to the drawing board Quote Link to comment Share on other sites More sharing options...
xyph Posted March 13, 2012 Share Posted March 13, 2012 Sorry to spam this thread. I've developed a 'smart' version of this script. It's quite a bit slower, though. What it does is it builds all possible category/column combinations for the average column length to the average column length + average category length, in intervals of one. The results are pretty sexy, and it could easily be optimized to skip %50+ of the iterations. This is more of a proof-of-concept. <style type="text/css"> #sitemap td { border: 1px solid black; vertical-align: top; font: 10px sans-serif; } #sitemap h3,ul { margin: 0; } #sitemap h3{ margin-top: 10px; } </style> <?php $data = array(); // Generate some random data for( $i=0,$imax=rand(15,30); $i < $imax; $i++ ) { $data[$i] = array('Category '.($i+1),array()); for( $j=0,$jmax=rand(0,10); $j < $jmax; $j++ ) $data[$i][1][$j] = 'Subcategory '.($j+1); } // Some parameters for our script. $columns = 5; // Number of columns $cat_value = 3; // Size value of each category $sub_value = 2; // Size value of each subcategory // // Get our category data $category_size = array(); foreach( $data as $key => $category ) $category_size[$key] = $cat_value + ($sub_value * count($category[1])); $average_cat = ceil( array_sum($category_size) / count($category_size) ); $average_col = ceil( array_sum($category_size) / $columns ); $difference = array(); $columndata = array(); $debug_sizes = array(); for( $i = $average_cat; $i > 0; $i-- ) { $curcol = 1; $colsize = 0; $sizes = array(); foreach( $data as $key => $category ) { if( $category_size[$key]+$colsize > $average_col+$i && $curcol < $columns ) { $sizes[$curcol] = $colsize; $debug_sizes[$i][$curcol] = $colsize; $curcol++; $colsize = 0; } $columndata[$i][$curcol][] = $key; $colsize += $category_size[$key]; } $debug_sizes[$i][$curcol] = $colsize; $sizes[$curcol] = $colsize; if( count($sizes) == $columns ) { sort( $sizes ); $difference[$i] = $sizes[($columns-1)] - $sizes[0]; } } asort( $difference ); echo '<table id="sitemap"><tr>'; foreach( $columndata[key($difference)] as $catarray ) { echo '<td>'; foreach( $catarray as $category ) { echo '<h3>'.$data[$category][0].'</h3><ul>'; foreach( $data[$category][1] as $sub ) { echo '<li>'.$sub.'</li>'; } echo '</ul>'; } echo '</td>'; } echo '</tr></table>'; echo '<h3>Debug Information</h3>'; echo '<strong>List of differences</strong><pre>'; print_r( array_unique($difference) ); echo '</pre><strong>Average Category Size: </strong>' . $average_cat . '<br>'; echo '<strong>Average Column Size: </strong>' . $average_col . '<br>'; echo '<strong>Actual Column Sizes:</strong><pre>'; print_r( $debug_sizes[key($difference)] ); echo '</pre>'; ?> Quote Link to comment Share on other sites More sharing options...
brooksh Posted March 13, 2012 Author Share Posted March 13, 2012 Your script looks like it can work, I just don't know how to implement it with my query. To grab the main category: SELECT DISTINCT category_name,category_id FROM db WHERE parent_id ='0' Order By category_name Then grab the subcategory: SELECT DISTINCT category_name,category_id FROM db WHERE parent_id = '$category_id' Order By category_name Quote Link to comment Share on other sites More sharing options...
scootstah Posted March 13, 2012 Share Posted March 13, 2012 Sorry to spam this thread. I've developed a 'smart' version of this script. It's quite a bit slower, though. What it does is it builds all possible category/column combinations for the average column length to the average column length + average category length, in intervals of one. The results are pretty sexy, and it could easily be optimized to skip %50+ of the iterations. This is more of a proof-of-concept. <style type="text/css"> #sitemap td { border: 1px solid black; vertical-align: top; font: 10px sans-serif; } #sitemap h3,ul { margin: 0; } #sitemap h3{ margin-top: 10px; } </style> <?php $data = array(); // Generate some random data for( $i=0,$imax=rand(15,30); $i < $imax; $i++ ) { $data[$i] = array('Category '.($i+1),array()); for( $j=0,$jmax=rand(0,10); $j < $jmax; $j++ ) $data[$i][1][$j] = 'Subcategory '.($j+1); } // Some parameters for our script. $columns = 5; // Number of columns $cat_value = 3; // Size value of each category $sub_value = 2; // Size value of each subcategory // // Get our category data $category_size = array(); foreach( $data as $key => $category ) $category_size[$key] = $cat_value + ($sub_value * count($category[1])); $average_cat = ceil( array_sum($category_size) / count($category_size) ); $average_col = ceil( array_sum($category_size) / $columns ); $difference = array(); $columndata = array(); $debug_sizes = array(); for( $i = $average_cat; $i > 0; $i-- ) { $curcol = 1; $colsize = 0; $sizes = array(); foreach( $data as $key => $category ) { if( $category_size[$key]+$colsize > $average_col+$i && $curcol < $columns ) { $sizes[$curcol] = $colsize; $debug_sizes[$i][$curcol] = $colsize; $curcol++; $colsize = 0; } $columndata[$i][$curcol][] = $key; $colsize += $category_size[$key]; } $debug_sizes[$i][$curcol] = $colsize; $sizes[$curcol] = $colsize; if( count($sizes) == $columns ) { sort( $sizes ); $difference[$i] = $sizes[($columns-1)] - $sizes[0]; } } asort( $difference ); echo '<table id="sitemap"><tr>'; foreach( $columndata[key($difference)] as $catarray ) { echo '<td>'; foreach( $catarray as $category ) { echo '<h3>'.$data[$category][0].'</h3><ul>'; foreach( $data[$category][1] as $sub ) { echo '<li>'.$sub.'</li>'; } echo '</ul>'; } echo '</td>'; } echo '</tr></table>'; echo '<h3>Debug Information</h3>'; echo '<strong>List of differences</strong><pre>'; print_r( array_unique($difference) ); echo '</pre><strong>Average Category Size: </strong>' . $average_cat . '<br>'; echo '<strong>Average Column Size: </strong>' . $average_col . '<br>'; echo '<strong>Actual Column Sizes:</strong><pre>'; print_r( $debug_sizes[key($difference)] ); echo '</pre>'; ?> You should polish that up a little and throw it in the snippet repo, it looks pretty useful. Quote Link to comment Share on other sites More sharing options...
brooksh Posted March 15, 2012 Author Share Posted March 15, 2012 Could you please give me an example array instead of the random array? I don't know too much. I know this isn't correct, but I'm just trying to figure this script out. $imax = array(Category:subcategory:subcategory,Category2:subcategory:subcategory) // Generate some random data for( $i=0,$imax=rand(15,30); $i < $imax; $i++ ) { $data[$i] = array('Category '.($i+1),array()); for( $j=0,$jmax=rand(0,10); $j < $jmax; $j++ ) $data[$i][1][$j] = 'Subcategory '.($j+1); } 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.