In this wyrld of fast-paced technology and even faster exchange of information, we are often beset by questions. How do I do this? Where do I do that? When will everything fit together? Sometimes, answers are are clearly visible. Sometimes we have to search.
At Ground Zero, we too have questions; but the first question is always the same: "Have we been here before?". These are our journals of excellent adventure. Come! See where we have been. Travel with us, and share. You will come to appreciate and understand … The Eureka Projects.
In our hearts, we all know that looks aren't everything, but few look away from glamor and glitter.
The following commented code is exactly the source of our first advertisement. Use the code and comments to suit your advertisement. The reader should note the leading credit. Indeed, most of our expertise evolves from experimentation, but credit is due our guides. Please be kind and respect our intellectual investment in like fashion, or by leaving a comment on this page.
May you accrue much good karma.
# CREDITS: # Valuable guidance for this flash script came from # SWFTOOLS # (http://www.swftools.org/swfc/swfc.html) # Particularly useful documentation is included in # project downloads # (http://www.swftools.org/download.html) # # DeepGeek contributed to this first advertisement with # emotion and many frustrating hours of experimentation # for desired transitions. # # File header specifies an output filename; # accepts all other default attributes .flash name="urth.swf" ## OBJECT DECLARATIONS ## Adjunct object files may declare fonts, sounds, images, ## stackable movies, and other objects. ## ## Local object definitions may include strings, sprites, lines, ## gradients, and much more. # Make object and font files accessible by the Flash compiler # Accessibility : in the source directory ## The TrueType Vera Font is a BitStream product ## available from The Free Software Desktop Project ## GNOME ## (http://www.gnome.org/fonts/) ## Not needed for this movie #.font Vera filename="Vera.ttf" # The TrueType WineTahoma Font derived from the BitStream Vera Sans font # and is renamed Tahoma in accordance with the former product's license. # WineTahoma is available at # WineHQ # (http://winehq.org) # The source repository has source code and binary files of a few useful # fonts # (http://source.winehq.org/source/fonts) .font Tahoma filename="tahoma.ttf" # A bit of searching located the Purisa TrueType font on my workstation. # /usr/share/fonts/truetype/thai/Purisa.ttf # Purisa is a free-licensed TrueType font, enhanced by developers from # Thai Linux Working Group # (http://linux.thai.net) .font Purisa filename="Purisa.ttf" # Graphics for MyDLL URTH products and publications are published at # Wyrld of Information .png urth "URTHLogo.png" .png doit "NoExcuse.png" # This advertisement is designed for QVGA placement # Designate 320 width and 240 height (pixel units) # Override the black defaults with white color and fill .box b1 320 240 color=white fill=white # Define string objects .text designer color=black font=Purisa text="Web services" .text training color=black font=Tahoma text="Office training" .text networks color=black font=Tahoma text="Network solutions" .text software color=black font=Tahoma text="Custom software" .text telephny color=black font=Tahoma text="VoIP configuration" .text phonenum color=black font=Tahoma text="(877)871.8784" # Initialize with the background override .put b1 # DOWN in the front, please; # and take all crying babies to the lobby for their comforting. .frame 1 # Pin the center of the motivational image to # the center of the movie box # at 60% of image size and full opacity .put doit pin=center x=160 y=120 scale=60% # During the next fifty frames (perhaps one second), # decrease opacity of the motivational image to 10%. # Then, pin an infinitesimal signature (logo) image # at the approximate center of "use" in the faded "excuse". .frame 50 .change doit alpha=10% .put urth pin=center x=240 y=120 scale=0% alpha=10% # For the next 15 frames (0.3 second), expand the logo # to 0.4 of original size. Then finish shrinking the motivation. .frame 65 .change urth scale=40% alpha=10% .jump doit alpha=0% # For the next 5 frames (0.1 second), expand and move the logo # to proportionately fill from the top at full opacity. Then place the # corner of our phone number at the approximate corner of # "877 U R 1 URTH" in the logo. Start the opacity at 10%, but the # string will have no dimension. .frame 70 .change urth pin=center x=160 y=48 scale=80% alpha=100% .put phonenum x=183 y=27 scale=0% alpha=10% # For the next 30 frames (0.6 second), expand the phone number # to translucently cover "877 U R 1 URTH" in the logo. # NOTE: 27% was determined by much painful experimentation .frame 100 .change phonenum scale=27% alpha=27% # For the next 15 frames, move the phone number to center # at the bottom of our frame at full opacity. # NOTE: The y=237 was logical. The scale=40% was # estimated in later stages of development. # The x=150 was purchased with some pain # and frequent adjustment during the movie # development. .frame 115 .change phonenum x=150 y=237 scale=40% alpha=100% # For the next 30 frames, let attention focus on the phone number. # # Begin streaming URTH products into a descending list at a rate of # approximately three products/second. Start each product at the # vortex of the logo spiral at full opacity and no dimension. Each # product descends to its list position at the 40% scale before the # next product is placed in the spiral vortex. .frame 145 .put designer x=150 y=40 scale=0% .frame 160 .change designer x=3 y=110 scale=40% .put training x=150 y=40 scale=0% .frame 175 .change training x=3 y=135 scale=40% .put networks x=150 y=40 scale=0% .frame 190 .change networks x=3 y=160 scale=40% .put software x=150 y=40 scale=0% .frame 205 .change software x=3 y=185 scale=40% .put telephny x=150 y=40 scale=0% .frame 220 .change telephny x=3 y=210 scale=40% # Let the audience digest information for the next # 2.3 seconds before starting the movie again. .frame 235 .frame 350 .end
| Attachment | Size |
|---|---|
| urth.swf | 126.92 KB |
If embedded maps are required on a Drupal site, the solution is barely more complicated than adding and enabling the gmap module with a registered Google Maps API key. The key, available for any web site that is free to consumers, is required to use the free beta service from Google and is valid for all directories of (only) the registered site.
To introduce capabilities of the gmap module, we give you a map of the primary staff at LS Net. You can click each of the map pins for more detail about our team. The blue circle describes the effective boundary of our on-site service without per-diem requirements.
The macro for the map (above) originated on a Drupal 5.9 site. The designated default input filter (full HTML) had to be modified to process the original ([gmap markers=drupal::36.66165,-80.92551 |zoom=16 |center=36.66165,-80.92551 |width=450px |height=250px |control=Small |type=Map]) gmap macro; a toggle at admin/settings/filters/3 enables the GMap filter for Full HTML. After the initial success, additional map pins and information balloons were added along with better map navigation controls in a larger area; the second generation macro became [gmap markers=drupal::36.66165,-80.92551:Woody<br>115 ½ W Grayson St<br>Galax, VA 24333<br>877.465.7638 + 36.71788894873847,-81.16682052612305: Miller<br>Elk Creek, VA + 36.69950,-81.09423:Tarvid<br>61 Caprine Ln<br>Independence, VA 24348 |zoom=11 |center=36.64473252005425,-81.12648010253906 |width=95% |height=430px |control=Large |type=Map]. A next step would be to generate a dynamic map which takes locative data from form inputs.
The next map enhancement modified the latitude and longitude for Tarvid to GPS-observed values (apparently Google or our Garmin requires significant calibration) … and the blue circle which roughly defines our one-day site-service area. This enhancement required just a little spherical geometry to approximate the theoretical center of our 200 kilometer service radius. The resulting gmap macro became [gmap circle=#55ddff/6/0.5: 36.68000,-81.05000 + 200 |markers=drupal::36.66165,-80.92551:Woody<br>115 ½ W Grayson St<br>Galax, VA 24333<br>877.465.7638 + 36.71789,-81.16682: Miller<br>Elk Creek, VA + 36.69950,-81.09423:Tarvid<br>61 Caprine Ln<br>Independence, VA 24348 |zoom=7 |center=36.68000,-81.05000 |width=95% |height=430px |control=Large |type=Map]
Array ( )
Similar to the declaration "The date is Thursday, 2008 August 21at 15:11:34 GMT", maps become outdated. Political boundaries, regional names, routes, residences, and terrain changes as a result of human actions. Shorelines, terrain, and populations change as a result of geological and other natural events. Maps are snapshots and drawings which represent a temporal state.
Similar to the declaration "Trash is collected on Tuesday mornings", a trash collection route map is nearly useless to someone seeking public transportation hubs. A map of restaurants can be useful, but not if you seek a nearby electrician. A street map is less useful than a topographical map with a street overlay when a line-of-sight is needed. Maps are best with appropriate information.
A tutorial for creating a dynamic GMap node would be useful as a Drupal resource. At the start of this book, is instruction for generating a static map. The macro for that first map approximates our tutorial default. The tutorial does not cover every possibility, but is quite lengthy for details of programmatic changes for markers, zoom level, map center, and several other mapping features. These things said, what follows is a journal of how this page's current code has developed.
|
Our content will be self-referencing, and the node id may be required for various reasons. This article is node #5, and we set an appropriate reference value. |
<?php
// REFERENCES // Make the node id available in context. $my_nid = 5; ?> |
Our form uses method="post" with action="/node/<?php print $my_nid; ?>" so values for our rendered GMap will be found in the global $_POST array. Other useful information (for example: browser configuration and client's IP address) is in the $_SERVER array. Trust us on this, you don't want to see the result of <pre><?php print_r ($_SERVER); ?></pre> … recursion is ugly and DEEP; <pre><?php print_r ($_POST); ?></pre> will, however, be interesting to watch as submitted form inputs change and impact our GMap macro.
A few preparations are necessary to generate the dynamic map. First, the GMap module must be installed, and configured. While configuring, a Google Maps API key for your site is required, and input formats for map nodes must include GMap Filters – without GMap Filters, macros will not be interpreted. Many configuration options are disabled until third-party enhancements are installed. If capacity for necessary adjustments is missing, re-read the first page of this book and set up a local Drupal sandbox. Second, content presentation improves by familiarity with HTML and CSS; that training is an entirely different tutorial … and not a difficult tutorial to find elsewhere. Some familiarity with Drupal API is also beneficial; tutorials abound, but take care to note the version of Drupal you use. Finally, client-side or server-side scripting skills are helpful; these, too, are not difficult tutorials to find. This tutorial will use PHP for server-side scripts but server-side scripted pages will not automatically update with user interactions. JavaScript is a popular client-side alternative, but clients may have essential interpreters disabled. Several languages are available for client-side and server-side scripts.
When set up correctly, drush is handy for Drupal site owners with sufficient shell access privilege. Installing the GMap module can be as simple as executing drush pm install gmap. We prefer the easy, downhill approach. We use drush — 'nuff said.
With or without shell access, FTP can do the job with write access to the web site file system. Download and expand the GMap module for your version of Drupal. You'll need a subdirectory in the web site root of sites/all/modules/. Recursively upload the expanded gmap subdirectory into sites/all/modules/.
Without write access to the web site file system, you'll need empowered help. Befriend your webmaster.
Look at the gmap/README.txt file for very detailed configuration instructions. Start by reading the Installation section. Sure, Configuration could be a better section name; regardless, you should attend these procedures for a most flexible installation.
Get a Google Map API key for your website. The key is free, but map scripts will not work without the proper authorization. When the gmap module is first enabled, append ?q=admin/settings/gmap to your site's base URL and go to that page. The administrator is alerted that the configured key is for another site. Dismiss the alert, and paste your site's key into the first text box. Click "Save configuration" when options you can change and wish changed are right.
NOTES: Some options are not configurable without additional interventions. As of Drupal 5.10. the location module will not work and, consequently, the gmap module loses some functionality. There was some location module functionality with Drupal 6.x before 6.4; that functionality is currently missing and many users bemoan "the gone old days".
Append ?q=admin/settings/filters to your site's base URL and go to that page. Configure every input filter in which creating maps is anticipated; on input filter configuration pages, check the box marked GMap filter before clicking the "Save configuration" button. You'll have basic gmap capacity after this step.
Be sure to add third-party scripts, add icons, and adjust themes for advanced functionality. After these optional modifications are done, new configuration options can be administrated.
Basis for our example map comes from the Build a GMap macro page. That page, and our example map uses substantial HTML with considerable CSS adjustments. These skills are not essential, but there is advantage in some knowledge.
The Drupal API makes life much easier when incorporating data from diverse sources. You could be less prepared … why not benefit from exquisitely documented open source software?
The power of dynamic content is processing. Use client-side scripts or use server-side scripts for light-weight processing.
Every dance must have a dancer. Every play must have an actor. Every song must have a singer. A company of such performers, particularly a traveling company, is called a troupe. Our map assembles a troupe of variables.
We will need some variables for adjusting our macro; these will make our map dynamic. We find several variable names in our sample macro. A study of Google's Map API illuminates variables' structures and guides our selection criteria.
Our application, while not a fully exploited map, is not a basic application and our troupe is a fair consideration. Some control of the map size and initial magnification is desirable. Also desirable are capacity to specify geolocations for the center of our map and at least one pinned location; the map center and a pinned location may require identical or distinct specifications. A map could require multiple groups with multiple locations; we establish framework for potential enhancements.
|
We used the following initialization script for our construct. Sequence arrays may have multiple instances; for the sake of simplicity, only singular sequence arrays are generated in this tutorial but the frameworks are included.
<?php
// VARIABLES
// If map control is not posted
// use defaults
$my_gmap =
(isset($_POST['map'])) ?
$_POST['my_gmap'] :
array (
'markers' => array(
array(
'icon' => 'vertex',
'geoloc' => array(
array(
'lat' => 36.66195,
'lon' => -80.92485
) ) ) ),
'zoom' => 16,
'center' => array(
'lat' => 36.66195,
'lon' => -80.9248
),
'width' => array(
'magnitude' => 450,
'unit' => 'px'
),
'height' => array(
'magnitude' => 250,
'unit' => 'px'
),
'control' => 'Small',
'type' => 'Map'
);
?>
|
After establishing default values in our construct, we enumerated finite option sets for a number of variables. These enumerations limit, but do not eliminate, invalid maps by restricting critical variables to acceptable values. While users may still posit useful values which request unreasonable computations (for example: a map width of 600 inches), we prohibit users from submitting invalid data by using select options sets. Dimensional and other limits should be an exercise in boundary checking … and that is a whole other education.
From our construct, enumerated options lists accommodate marker icons, zoom levels, dimensional units, map controls and map types. Giving all enumerations is more than necessary for instructional purposes; the most diverse is sufficient for demonstration. The most diverse enumeration, of map types, follows.
<?php
// Enumerate map type options to limit occurrence of empty maps
$types = array('Map' =>'Standard street map',
'Satellite'=>'Standard satellite map',
'Hybrid' =>'Hybrid satellite map',
'Physical' =>'Physical feature map');
?>
Behind the scenes of every great production, is superbly choreographed technical support. Technical support is two-thirds of the "Lights! Camera! ACTION!" mantra. Without light or camera, action is futile. So … before the dance, we position the lights, adjust the audio, and turn on the magic.
Previously, we mentioned the need for HTML and CSS. That is, indeed, much of the technical support in this production. Tables were carefully constructed for a visually pleasing and logical placement of form inputs. Our form contains a table of two rows. The first row contains the Markers fieldset which wraps around the marker groups. The second row contains configuration inputs for the map presentation. We will give enough detail of each row, to guide development of your similar applications.
The Markers fieldset organizes marker groups. Each marker group uses a common map pin and may designate multiple locations. Marker groups may designate polygons with lines connecting the designated locations, sequentially. Marker groups may, also, define a curved boundary with centers and foci and arc segments. Sure, there is only a single group with a single location, but the structure is ready for more.
The configuration inputs of the second row allow for setting an initial zoom in a custom-sized map view. The map view can be centered around any of the designated map pins or any other specified point as defined by a latitude and longitude. Yes! there's only one map pin. More, at this stage, would scare amateurs. We'll do multiple map pins with curves and clusters in the next tutorial. For now, enjoy changing the view of a single pin and use the Build a GMap macro page for multiple location and marker types. Maybe changing the pan and zoom control and the map type will compensate the lack of multiple pins.
There are four types of inputs in our form. Six inputs (two latitude and longitude pairs, and magnitude for width and height) use text inputs. These are simple inputs and contain a name and value from their previously assigned value. The inputs are intended for numeric values and validation code is not used. For whatever pleasure derives, provide non-numeric data if failures are your hope. A representative labeled text input would be for the map pin latitude.
<?php // Generate a label and text input for latitude ordinate print ' <label for ' . $marker_array . '_' . $marker_loc_array . '_lat">Latitude </label>'; print '<nput type="text" id="' . $marker_array . '_' . $marker_loc_array . '_lat"'; print ' name="my_gmap[markers][' . $marker_array . '][geoloc][' . $marker_loc_array . '][lat]"'; print ' value="' . $my_gmap['markers'][$marker_array]['geoloc'][$marker_loc_array]['lat']; print '" size="12"> '; ?>
Of course, code can be added to check for reasonable values. However, there is a more reasonable alternative: create a modified webform for map definitions … input validations are easily added. Why didn't we use a webform? Primarily, because hindsight is 20/20. HTML came, first, to mind – there is such adventure in our webmaster's mental archive.
The more plentifully utilized of our inputs are selects. Generation of those controls and associated labels are trivial tasks, but showing each generation is barely more service than showing one. Each select script uses the same general format; a common function for that generation is left as a programming exercise for another tutorial. The script for generating the map overlay select follows.
<?php
print '<label for "type">Overlay </label>';
print '<select id="type" name="my_gmap[type]">
';
foreach($types as $key => $value) {
print '<option value="' . $key . '"';
if ($my_gmap['type'] == $key) {
print ' SELECTED';
}
print '>' . $value . '</option>
';
}
unset($value);
unset($key);
print '</select><br>
';
?>
There are, also two radio inputs for designating the center of our map. The default radio input directs using the location of our pinned location as the map center. The option is manual designation of the map center at the previously designated map center or another location as described by the user. There are only two radio buttons, and the difference is significant enough to warrant reporting both in context.
<?php
print '<input type="radio" name="center" value="pin" checked="checked"> Center map at
';
print 'group
';
print '<select name="cgrp">
';
$gmax = count($my_gmap['markers']);
for ( $selector = 0; $selector < $gmax; $selector++) {
print '<option value="' . $selector . '">' . $selector . '</option>
';
}
print '</select>
';
print ' :: location ';
print '<select name="cloc">
';
$lmax = count($my_gmap['markers'][--$gmax]['geoloc']);
for ( $selector = 0; $selector < $lmax; $selector++) {
print '<option value="' . $selector . '">' . $selector . '</option>
';
}
print '</select><br>
';
print '<input type="radio" name="center" value="spec"> Center map at
';
print '<label for "map_lat">Latitude </label>
';
print '<input type="text" id="map_lat" name="my_gmap[center][lat]"';
print ' value="' . $my_gmap['center']['lat'] .'" size="12">
';
print '<label for "map_lon">Longitude </label>
';
print '<input type="text" id="map_lon" name="my_gmap[center][lon]"';
print ' value="' . $my_gmap['center']['lon'] . '" size="12"><br>
';
All of the GMap variables are previously documented. We list them, this time, with default values and associations for working variables to $_POST variables.
| default | ||
| $my_gmap | array() | $_POST['my_gmap'] |
| $my_gmap['markers'] | array() | $_POST['my_gmap']['markers'] |
| $my_gmap['markers'][]['icon'] | 'vertex' | $_POST['my_gmap']['markers][]['icon'] |
| $my_gmap['markers'][]['geolocation'] | array() | $_POST['my_gmap']['markers'][]['geolocation'] |
| $my_gmap['markers'][]['geolocation'][]['lat'] | 36.66195 | $_POST['my_gmap']['markers'][]['geolocation'][]['lat'] |
| $my_gmap['markers'][]['geolocation'][]['lon'] | -80.92485 | $_POST['my_gmap']['markers'][]['geolocation'][]['lon'] |
| $my_gmap['zoom'] | 16 | $_POST['my_gmap']['zoom'] |
| $my_gmap['width']['magnitude'] | 450 | $_POST['my_gmap']['width']['magnitude'] |
| $my_gmap['width']['unit'] | 'px' | $_POST['my_gmap']['width']['unit'] |
| $my_gmap['height']['magnitude'] | 250 | $_POST['my_gmap']['height']['magnitude'] |
| $my_gmap['height']['unit'] | 'px' | $_POST['my_gmap']['height']['unit'] |
| $my_gmap['center']['lat'] | 36.66195 | $_POST['my_gmap']['center']['lat'] |
| $my_gmap['center']['lon'] | -80.92485 | $_POST['my_gmap']['center']['lon'] |
| $my_gmap['control'] | 'Small' | $_POST['my_gmap']['control'] |
| $my_gmap['type'] | 'Map' | $_POST['my_gmap']['type'] |
| 'pin' | $_POST['center'] | |
| 0 | $_POST['cgrp'] | |
| 0 | $_POST['cloc'] | |
| 'Show my map' | $_POST['map'] | |
| 'Start over' | $_POST['reset'] |
When the curtain raises and everything is in place, one actor steals the show. We gather all the facts to generate our GMap macro.
<?php print ' ['; print 'gmap'; print ' markers=' . $my_gmap['markers'][0]['icon'] . '::'; print $my_gmap['markers'][0]['geoloc'][0]['lat'] . ',' . $my_gmap['markers'][0]['geoloc'][0]['lon']; print ' |zoom=' . $my_gmap['zoom']; print ' |width='; print $my_gmap['width']['magnitude'] . $my_gmap['width']['unit']; print ' |height='; print $my_gmap['height']['magnitude'] . $my_gmap['height']['unit']; print ' |center='; print $my_gmap['center']['lat'] . ',' . $my_gmap['center']['lon']; print ' |control=' . $my_gmap['control']; print ' |type=' . $my_gmap['type']; print '] '; ?>
We hope you enjoyed the show. Kindly tip the usher on your way out.
At some time in our past a first statement issued. In most creation stories, those first words announce beginning: "Let there be …". Surely, those are great words; yet, they are not great for simply being first words. These words are great, also, for their source, their pronounced authority, their portrayed creativeness, and their plenteous repetitions.
In like fashion, web sites begin in chaos — a single expression to change a vast emptiness. Are those primordial pronouncements, also, great? In the beginning, these are mere disturbances of status quo which may (or may not) be destined for greatness.
What of later statements? John Kennedy's much maligned "Ich bin ein Berliner" announcement resonates much more than Marie Antoinette's attribution "Qu'ils mangent de la brioche". Does recency make one jelly donut more memorable than a national supply of cake? Will a yet unsaid misstatement overtake the popularity of both? Certainly this is true; but, what will be the superlative qualifications?
Fireworks, catchy titles, …