Changes between Initial Version and Version 1 of PHPDynLegend


Ignore:
Timestamp:
Jan 27, 2009, 9:55:03 AM (15 years ago)
Author:
jmckenna
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PHPDynLegend

    v1 v1  
     1= Creating and Using Dynamic Legends / Layer Controls Using PHP MapScript =
     2
     3This page created by Chip Hankley.
     4
     5== Additions ==
     6
     709/12/2002 - Legend script writes to a static HTML file, which is then included(). The script compares the file date for the mapfile with the static HTML file. If the static HTML file does not exist, OR, the mapfile is newer, a new legend is created. This saves on server processing... there's no reason to generate a new legend w/ each request... it should only be regenerated when needed.
     8
     909/12/2002 - Now assesses whether or not layers are outside of MINSCALE or MAXSCALE bounds, and responds by disabling the checkbox and making the layer description gray.
     10This document describes how to create dynamic legends / layer controls using PHP !MapScript.
     11
     12== Introduction ==
     13
     14Controlling layers (i.e. telling !MapServer which layers to draw) can be one of the trickier part to designing and implementing a !MapScript application. Encapsulating this control in a meaningful legend is often even more difficult (at least it was for me!).
     15
     16The snippet of PHP code at the bottom shows how you can use !MapScript to dynamically create a legend with controls for turning layers on and off.
     17
     18There are several caveats to following this:
     19
     20  1) The name that appears in the legend is drawn from the Metadata tag (see the sample layer definition below).
     21  2) Everything must have a group name.
     22  3) Layers that have multiple classes need to have names for each class
     23  4) Layer controls (i.e. the checkboxes) are named with the with a 'lyr' prefix... i.e.
     24       input type='checkbox' name='lyrRoads' value='roads'>
     25     The script depends on this... so you can't have any other form controls that are prefixed 'lyr.'
     26  5) You now need to specify some of paths at the beginning of the script.
     27
     28Note that this is not meant to be an exhaustive script... it's really just set up to show how you would do this. It's pretty simple, and could easily be modified for changing needs. I took the basic concept for this out of the example script (test_draw_legend_icon.phtml) that comes with the !MapServer source (in the PHP directory). Along those lines, I put the script together so that, after entering a valid mapfile name, you can test it out by submitting the form and watching how layer status state is maintained.
     29
     30Also note that I used CSS to make the 'legend' look nice... but you could just as easily use tables or other HTML tools to control indents, etc.
     31
     32== Sample Layer Definition ==
     33{{{
     34...
     35LAYER
     36  NAME "roads"
     37  GROUP "Base Data"
     38  METADATA
     39    LYRNAME "Roads"
     40  END
     41  STATUS ON
     42  TYPE LINE
     43  DATA ...
     44  CLASSITEM 'ROADCLASS'
     45  CLASS
     46    NAME 'Highways'
     47    EXPRESSION '5'
     48    COLOR 255 0 0
     49    SYMBOL 'solid_line'
     50    SIZE 3
     51    OVERLAYCOLOR 0 0 0
     52    OVERLAYSYMBOL 'solid_line'
     53    OVERLAYSIZE 1
     54  END
     55  CLASS
     56    NAME 'Major Roads'
     57    EXPRESSION '7'
     58    COLOR 0 0 0
     59  END
     60  CLASS
     61    NAME 'Local Roads'
     62    EXPRESSION /./
     63    COLOR 204 204 204
     64  END
     65END
     66...
     67}}}
     68== Dynamic Legend Script ==
     69{{{
     70<?
     71$path_to_mapfile = "C:\\Inetpub\\wwwroot\\Lockport\\lockport.map";
     72$path_to_legend = "C:\\Inetpub\\wwwroot\\Lockport\\legend\\";
     73$url_to_legend = "legend/";
     74$map = ms_newMapObj($path_to_mapfile);
     75$img = $map->draw();
     76$url = $img->saveWebImage(MS_PNG, $map->transparent, $map->interlace, 50);
     77
     78//Get the last modified date from the mapfile and the legend
     79$mapfile_modtime = filemtime($path_to_mapfile);
     80//use '@' to suppress error when there is no 'legend.php' file.
     81// In this case the default action will be to create one.
     82$legend_modtime = @filemtime($path_to_legend . "legend.php");
     83
     84//get all layers
     85$allLayers = $map->getAllLayerNames();
     86//get all of the group names
     87$groupNames = $map->getAllGroupNames();
     88
     89//Set the status of various layers based
     90// on what is checked. This only needs
     91// to be done if this is not the first
     92// load. On the first load, we will simply
     93// use the STATUS values as set in the map
     94// file
     95if (!empty($_POST)) {
     96  //Turn all layers off
     97  foreach($allLayers as $a) {
     98    SetStatus($a, 0);
     99  }
     100  //Turn the layers ON that were checked
     101  // in the previous submit. Since we named
     102  // the checkboxes that control layer display
     103  // with a prefix of 'lyr', we can basically
     104  // loop through the submitted form variables
     105  // and key in on those that relate to layer
     106  // control.
     107  $POST_KEYS = array_keys($_POST);
     108  foreach($POST_KEYS as $a) {
     109    if (substr($a, 0, 3) == "lyr")
     110      SetStatus($_POST[$a], 1);
     111  }
     112}
     113//Check the scale status for each layer. Dump the
     114// results into an array to access when building the legend
     115// NOTE that in an application, you would need to call this
     116// AFTER you draw the map, or scale will not be properly
     117// set.
     118foreach($allLayers as $a) {
     119  $LayerScale[$a] = CheckScale($a);
     120}
     121
     122//Next line is for demo purposes... encapsulating this in a form
     123// just allows us to review the results. and see that it is
     124// working. Normally, you would probably include all of your
     125// map related info in one form.
     126echo "<form method=POST action=dyn_legend.php>";
     127
     128//Only generate the legend IF the mapfile is older than the
     129// legend file.
     130if ($mapfile_modtime > $legend_modtime) {
     131//=======================================================================
     132// Generate a legend dynamically, and write it to a static HTML file
     133//=======================================================================
     134//delete all of the existing files in the LEGEND directory
     135system("del " . $path_to_legend . " /q");
     136$img_count = 0;
     137
     138//create a file to write the HTML to
     139$fp = fopen($path_to_legend . "legend.php", "w+");
     140
     141fwrite($fp, "<span style=\"font-family: arial; font-size: 11pt; font-weight: bold; padding-left: 5px\">Legend</span>\n<HR>\n");
     142fwrite($fp, "<div style=\"padding-left:10px\">\n");
     143
     144foreach($groupNames as $a) {
     145  fwrite($fp, "<span style=\"font-family: arial; font-weight: bold; font-size: 10pt\">" .$a . "</span><BR>\n");
     146  foreach($map->getLayersIndexByGroup($a) as $b) {
     147    $layer = $map->getLayer($b);
     148    $title = $layer->getMetadata("LYRNAME");
     149    $name = $allLayers[$b];
     150    $checked = GetStatus($map, $name);
     151
     152    //Images
     153    if ($layer->type==3) {
     154      fwrite($fp, "<span style=\"font-family: arial; font-size: 9pt; padding-left: 10px;");
     155      fwrite($fp, "<?echo \$LayerScale[$name][fontcolor]?>\"><input type=\"checkbox\" name=\"lyr$name\" value=\"$name\" <? echo \$LayerScale[$name][checked]; echo \$LayerScale[$name][disabled]?>>$title</span><BR>\n");
     156    }
     157    //Layers with one class
     158    elseif ($layer->numclasses <= 1) {
     159      $myClass = $layer->GetClass(0);
     160      $img = $myClass->createLegendIcon($map->keysizex, $map->keysizey);
     161      $img_name = $name . ++$img_count . ".png";
     162      $img->saveImage($path_to_legend . $img_name, MS_PNG, 0, 0, 0);
     163      $url = $url_to_legend . $img_name;
     164      fwrite($fp, "<span style=\"font-family: arial; font-size: 9pt; padding-left: 10px; <?echo \$LayerScale[$name][fontcolor]?>\"><input type=\"checkbox\" name=\"lyr$name\" value=\"$name\" <? echo \$LayerScale[$name][checked]; echo \$LayerScale[$name][disabled]?>>");
     165      fwrite($fp, "<IMG SRC=\"" . $url . "\">  " . $title . "</span><BR>\n");
     166    }
     167    //Layers with multiple classes
     168    else {
     169      fwrite($fp, "<span style=\"font-family: arial; font-size: 9pt; padding-left: 10px; <?echo \$LayerScale[$name][fontcolor]?>\"><input type=\"checkbox\" name=\"lyr$name\" value=\"$name\" <? echo \$LayerScale[$name][checked]; echo \$LayerScale[$name][disabled]?>>");
     170      fwrite($fp, "  $title");
     171      fwrite($fp, "<div style=\"font-family: arial; font-size: 8pt; padding-left: 20px;<?echo \$LayerScale[$name][fontcolor]?>\">");
     172      for ($j=0; $j<$layer->numclasses; $j++) {
     173        $myClass = $layer->GetClass($j);
     174        $img = $myClass->createLegendIcon($map->keysizex, $map->keysizey);
     175        $img_name = $name . ++$img_count . ".png";
     176        $img->saveImage($path_to_legend . $img_name, MS_PNG, 0, 0, 0);
     177        $url = $url_to_legend . $img_name;
     178        fwrite($fp, "<IMG SRC=\"" . $url . "\">  " . $myClass->name . "<BR>");
     179      }
     180      fwrite($fp, "</div>");
     181    }
     182  }
     183}
     184fwrite($fp, "</div>\n");
     185fclose($fp);
     186//=======================================================================
     187// End of dynamic legend creation, and write it to a static HTML file
     188//=======================================================================
     189}
     190
     191include($path_to_legend . "legend.php");
     192
     193echo "<input name=\"SubmitButton\" type=\"submit\" value=\"GO!\">";
     194echo "</form>";
     195PHPINFO(INFO_VARIABLES);
     196function GetStatus($map, $LayerName)
     197{
     198  $Layer = $map->getlayerbyname($LayerName);
     199  if ($Layer->status)
     200    $Status = " checked";
     201  else $Status = "";
     202  return ($Status);
     203}
     204function SetStatus($lyrname, $value) {
     205  $map = $GLOBALS["map"];
     206  $layer=$map->getlayerbyname($lyrname);
     207  $layer->set("status", $value);
     208}
     209function CheckScale($lyrname) {
     210  $map = $GLOBALS["map"];
     211  $layer=$map->getlayerbyname($lyrname);
     212  //echo "<P>MapScale: $map->scale<BR>MaxScale: $layer->maxscale<BR>MinScale: $layer->minscale</p>";
     213  if ($layer->maxscale == -1 AND $layer->minscale == -1) {
     214    $scale_params["fontcolor"] = " color: black; ";
     215    $scale_params["disabled"] = "";
     216  }
     217  elseif ($map->scale > $layer->maxscale AND $layer->maxscale <> -1) {
     218    $scale_params["fontcolor"] = " color: gray; ";
     219    $scale_params["disabled"] = " disabled";
     220  }
     221  elseif ($map->scale < $layer->minscale AND $layer->maxscale <> -1) {
     222    $scale_params["fontcolor"] = " color: gray; ";
     223    $scale_params["disabled"] = " disabled";
     224  }
     225  else {
     226    $scale_params["fontcolor"] = " color: black; ";
     227    $scale_params["disabled"] = "";
     228  }
     229  $scale_params["checked"] = GetStatus($map, $lyrname);
     230  return $scale_params;
     231}
     232
     233?>
     234}}}