Author Archive

Toggle Map Style and the Polygons Shown

In my previous Google Maps examples, I store all objects such as polygons and markers in an overlayArray.  Having a “global” theme change that doesn’t just alter the mapStyle, but also polygons is as simple as looping through your Array and setting options.   Here I’m using variable t1 to control the true/false variable, on a live site you should probably do something local such as adding a Class name to the button.

 

  var t1 = true;
    $("#toggle-theme").click(function(e) {
        e.preventDefault();
        if (t1) {
            t1 = false;
            map.setOptions({
                styles: mapstyleDefault
            });
            for (var i in overlayArray) {
                overlayArray[i].setOptions({
                    strokeColor: '#ff0000',
                    fillColor: '#ff0000',
                })
            }
        } else {
            t1 = true;
            map.setOptions({
                styles: mapstyleAlternate
            });
            for (var i in overlayArray) {
                overlayArray[i].setOptions({
                    strokeColor: '#29800b',
                    fillColor: '#29800b',
                })
            }
        }
    
    });

Remove Overlays

I find the most elegant way to deal with Google Maps objects from markers to polygons is to push them to a global array.  The simplest popular method is merely to use this array for clearing all objects.  The example below does that and references a separate InfoWindow array.  Simply setMap null, close the windows, and if needed reset all the arrays to 0.

function clearOverlays() {
    for (var i in overlayArray ) {
      overlayArray[i].setMap(null);
    }
    for (var i in infowinArray ) {
        infowinArray[i].close();
    }
    overlayArray.length = 0;
    infowinArray.length = 0;
};

Though this will suffice for simple loop operations where you basically call back and forth a few items, I found that for more complex objects and maps, a fancier robust function is needed to manage. In my case, I am storing a “complex” polyline, that is many polyline path segments which must be individually rendered.  For example if your path loops around a city, it’s clear you won’t be able to accomplish rendering that in one path.  KML notation already recognizes this and so groups many LineSegments into a MultiGeometry structure.  Manipulation of a KML layer’s stroke, color, etc is easy.  Unfortunately Google Maps does not have a multigeo, and using a Polygon object will not suffice as it automatically draws in the end points.  As well, your polylines may not necessarily connect but are associated with each other.

Here is my revised kitchen sink clear overlay function that offers a target and exclusion option.

  • clearOverlays(“all”) will simply result in everything being removed.
  • clearOverlays(20) or clearOverlays([20, 22, 25]) results in clearing only the targeted numbers being removed.
  • clearOverlays(“all”, 20) or clearOverlays(“all”, [20, 22, 25]) results in everything except the number or array being targeted.
  • Note you can’t do both such as clearOverlays(22, [80]), it will simply ignore the exclusion and go with the targeted item.  Of course this is also illogical.
  • The function takes into account, as in my case, whether you have an array within an array (“embedded”) as is required for grouping polylines or markers.
function clearOverlays(target, exclusion) { 

    // this function to go a level down into the array of objects (polylines, etc)
    function removeObj(a) { 
        if (typeof a[i].setMap == "function") { 
            for (var i in a) { 
                a[i].setMap(null);
            }
        }
    }

    if (target !== "all") { // just targeting something for removal

        if (typeof target == "number" || typeof target == "string") { 
            for (var i in overlayArray) { 
                if (overlayArray[i][0] == target) { removeObj(overlayArray[i][1]); }
            }
        } else { // if array

            for (var i in overlayArray) { 
                if (inArray(overlayArray[i][0], target)) { 

                    if (typeof overlayArray[i][1].setMap == "function") { 
                        overlayArray[i][1].setMap(null); 
                    } else { 
                        removeObj(overlayArray[i][1]);
                        }
                };
            };

        }

    } else { 

        if (exclusion == "") {  // target all, remove everything
            for (var i in overlayArray) { 
                if (typeof overlayArray[i][1].setMap == "function") { 
                    overlayArray[i][1].setMap(null); 
                    } 
                removeObj(overlayArray[i][1]);
                }
            } else { // target all but exclusions
            for (var i in overlayArray) { 
                if (inArray(overlayArray[i][0], exclusion)) { //ignore 
                } else {
                    removeObj(overlayArray[i][1]);
                    }
                }
            }
    };    

    function inArray(needle, haystack) { // needle being a string
        for (var i = 0; i < haystack.length; i++) {
            if (haystack[i] == needle) return true;
        }
        return false;
    }
};

 

Google Maps KML Toggle

My new KML toggle method is as follows which more logically lays out the variables and functions involved. The true improvement is that in order to add new KML files to the map, you simply add a new row to array kml. The code generates the rest. This code is literal easily adaptable to more asynchronous applications.

Code below or view it on Github.

<html>
<head>
<title>KML Toggle Example</title>

 <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>

 <script type="text/javascript">

    // define some variables to be used later
    var map;
    var overlays = [];
    var kml = {
        a: {
            name: "MPLS/STPL",
            url: "https://maps.google.com/maps/ms?authuser=0&vps=5&ie=UTF8&msa=0&output=kml&msid=212971981154994583939.0004b06640255267e038c"
        },
        b: {
            name: "Bicycling Tour Routes",
            url: "https://maps.google.com/maps/ms?authuser=0&vps=4&ie=UTF8&msa=0&output=kml&msid=212971981154994583939.0004902a1824bbc8c0fe9"
        }, 
    // keep adding more, the url can be any kml file
    };

    // initialize our goo
    function initializeMap() {
        var options = {
            center: new google.maps.LatLng(44.9812, -93.2687),
            zoom: 13,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(document.getElementById("map_canvas"), options);

        createTogglers(); // in this example I dynamically create togglers, you can otherwise use jQuery
    };

    google.maps.event.addDomListener(window, 'load', initializeMap);

    // this does all the toggling work, id references the a b names I gave the kml array items

    function toggleKML(checked, id) {

        if (checked) {

            var layer = new google.maps.KmlLayer(kml[id].url, {
                preserveViewport: true,
                suppressInfoWindows: true 
            });

            kml[id].obj = layer; // turns the layer into an object for reference later
            kml[id].obj.setMap(map); // alternative to simply layer.setMap(map)
        }
        else {
            kml[id].obj.setMap(null);
            delete kml[id].obj;
        }

    };

    // in this example create the controls dynamically, prop is the id name 
    function createTogglers() {

        var html = "<form><ul>";
        for (var prop in kml) {
            html += "<li id="selector-" + prop + ""><input type='checkbox' id='" + prop + "'" +
            " onclick='highlight(this, "selector-" + prop + ""); toggleKML(this.checked, this.id)' />" +
            kml[prop].name + "</li>";
        }
        html += "<li class='control'><a href='#' onclick='removeAll();return false;'>" +
        "Remove all layers</a></li>" + 
        "</ul></form>";

        document.getElementById("toggle_box").innerHTML = html;
    };

    // easy way to remove all objects, cycle through the kml array and delete items that exist
    function removeAll() {
        for (var prop in kml) {
            if (kml[prop].obj) {
                document.getElementById("selector-" + prop).className = 'normal'; // in normal js, this replaces any existing classname
                   document.getElementById(prop).checked = false;
                kml[prop].obj.setMap(null);
                delete kml[prop].obj;
            }
        }
    };

    // append class on select, again old school way 
    function highlight(box, listitem) {
        var selected = 'selected';
        var unselected = 'normal';
        document.getElementById(listitem).className = (box.checked ? selected : unselected);
    };

 </script>

<style type="text/css">
#toggle_box { position: absolute; top: 100px; right: 30px; padding: 10px; background: #fff; z-index: 5; box-shadow: 0 5px 10px #777 }
ul { margin: 0; padding: 0; font: 100 1em/1em Helvetica; }
ul li { display: block; padding: 10px; margin: 2px 0 0 0; transition: all 100ms ease-in-out 600ms; }
ul li a:link { border: 1px solid #ccc; border-radius: 4px; box-shadow: inset 0 5px 20px #ddd; padding: 10px; font-size: 0.8em; display: block; text-align: center; }
.selected { font-weight: bold; background: #ddd; }
</style>

</head>
<body>
<div id="map_canvas" style="width: 100%; height: 600px;"></div>
<div id="toggle_box"></div>
</body>
</html>

Convert KML to PolyLine

To convert a KML file to a native Google Maps rendered polyline is essentially the process of parsing the KML, which is XML syntax, into its constituent parts, that being coordinates within a object.

I found the conversion necessary in the process of pulling stored KML data from a Google Fusion Table. If the KML data is stored as Location type, then it will return a MVCArray which can easily be picked apart with for loops to extract the coordinates. However, I have discovered that Fusion Tables has some issues or limitations with very complex KML objects that are not yielding all coordinate arrays, resulting in a half-rendered line. As such I’ve “manually” parsed the KML as a string. The two methods are presented.

success: function(data) {

var rows = data['rows'][0];

for (var i in rows) { 

var geo = rows[i]['geometries'];

	for (var j in geo) { 
	var linesegment = geo[j]['coordinates'];
	drawLine(linesegment);
	};

}


function drawLine(linesegment) { 
	var coordArray = [];
	console.log("rows");
	for (var i in linesegment) {
		var lat = linesegment[i][1];
		var lng = linesegment[i][0];
		var lineCoord = new google.maps.LatLng(lat, lng);
		coordArray.push(lineCoord);
	}

	var randomnumber = Math.floor(Math.random()*7);

	var colors = ["#FF0000", "#00ffff", "#FF00ff", "#Ffff00", "#555555", "#222222"];

  var routeLine = new google.maps.Polyline({
    path: coordArray,
    strokeColor: colors[randomnumber],
    strokeOpacity: 1.0,
    strokeWeight: 4,
  });

  routeLine.setMap(map);
  
}

Header Image via Featured Thumbnail

A lot of sites employ a header splash, notably photographer websites.  It is a highly requested feature of clients.  Fortunately WordPress has an easy hook with its featured image (thumbnail) setting that will allow an admin to set whatever image they wish for each post or page.  First, in functions.php, activate thumbnail support.

add_theme_support( ‘post-thumbnails’ );

Then in your theme file, such as header.php, call it forth.

<?php if (has_post_thumbnail( $post->ID ) ) : // is thumbnail set?
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), ‘single-post-thumbnail’ ); // grab image attr array ?>
<header class=”main-header” style=”background-image: url(‘<?php echo $image[0]; // the first array item is the src ?>’)”>
<?php else : ?>
<header class=”main-header” style=”background-image: url(‘<?php bloginfo(‘template_url’); // define a default in your theme folder ?>/images/defaultbg.jpg’)”>
<?php endif; ?>

Then CSS3’s background-size will do you well.   Alternatively you could have it echo into an img tag and set width, height 100% auto.

 

Thought Process of Working in Google Maps

Sometimes as a front-end you think by taking the “back-end” methodology route, you can accomplish great feats. In the end, the answer is often much simpler than you think. Such as in this example.

I need to find the coordinates of the center of a polygon.

Easy right?

First problem, the polygon is stored in KML format in a Fusion Table. Let’s use my awesome getJSON call from last year to retrieve the data, oh wait, the API has changed, okay let’s go to their ajax example even though it’s technically equivalent. Now the data is an object, oh I can’t work with an object.

Google, google, google…

Let’s try Google visualization since they enjoy offering different ways to find the same carrot. Oh okay I have to load Goog JS. More resources, the better! A dozen for loop iterations later, I still have an object.

Okay let’s try stringifying by manually pulling out the coordinate information from the KML object with js splits, parseFloats and jQ text() conversions. Great now I have 20 lines of coordinate data because it’s a complex polygon.

Except to retrieve the bounds of the polygon, I need a RECTANGLE. Argh! Perhaps if I become a zen master of algorithms, I can determine which four lines of coordinates are the approximate four corners of an averaged rectangle. Easy!

Google, google, google…

Try getCenter, getBounds and anything that gets something out of nothing. Thinking I need to extract the raw KML formatted data as is and then use to to call forth KmlLayer inline. Half an hour later, I realize I’m trying to thrust a packet of data into what is only a URL call.

Maybe I should extract the first coordinate point of each polygon via strlens and use that as an approximated marker location with some math adjustments. Oh wait, every polygon’s first coordinate point is all over the place. Banish the thought.

Google, google, google…

Answering some random questions on StackOverflow that do not relate but came up anyway.

Upon consulting every inch of Google Maps V3 developer guide, I come to realize I just need to zero in on the infoWindow’s self-centered latLng itself.

Several hours and dozens of lines of test code later, I actually needed just one line of code.

Yes sir, you can have labels in the middle of each polygon now.

/die.

Does Lean UX Replace Style Guides

Two years ago I read a great article by Smashing Magazine on “Style Guidelines for Brands and Websites” which suggests designers offer style guides to clients post-project. Often in the rush to the deadline, we forget that a website is never completely done and will continue to live on, organically changing and adapting itself. Having a style guide certainly gives the client evidence that actual strategic thought went into development of their brand. At the University of Minnesota, I became very familiar with their style guides during HTML 4.01’s reign. From a systematic organizational perspective, style guides were a doctrine that constrained specific uses but also allowed room for creativity in the spirit of the guide.

When I think about traditional style guides in the context of Lean UX, in reducing waste from iterative processes, I realize they are paradoxically outmoded and transgressed. Style guides can take many forms and for web often manifest in layout standards (wireframes) and graphic standards (color, shape, size, position). In essence a web style guide creates a prototype’s framework for you, and it’s up to you to fill in the pieces. In an ever evolving start-up environment, the visual standards are constantly changing, being thrown away or restructured into new forms. Why bother creating a guide when you know tomorrow even the very fundamental aspects of your product will change.

Now, at the same time, a style guide can act as a fundamental bedrock because it infuses the overall process with a sense of purpose and unity. Style guides come from the print environment where seemingly minor factors like line-height and line thickness can make or break. As we know from conceptual design or product design in general, that form is sometimes eminently more important than function (assuming the function is worthy). Twitter and Facebook are essentially communication mediums but their forms, in 140 characters or in dynamic multi-level posts, change the user experience. Mac OS X is a system that clearly has a style guide, that very specifically dictates every visual graphic to the point where outside developers and their designers must follow the edict. Ironically it is Windows that has shown a penchant for anything goes, and we know how that’s turned out.

Style guides are different from documentation. Jeff Gothelf writes in “Lean UX Is Not Anti-deliverable” (5/23/2012):

The focus should still be to design the best experience while minimizing the amount of time designing the wrong ones — not to design documentation that describes these design hypotheses.

Lean UX is about a specific design solution as a scientific question. Does my new app interface do what it intends without any instruction? The documentation outlining wireframes and hierarchy are what needs to go. On the other hand I see style guides as addressing a higher level question, whether the design communicates not just purpose but cohesion with the message, brand and experience. If anything, style guides answer questions of the strategic plan. The new Digg is perhaps the best example of a redesign that, one can argue, does exactly the same thing, but in form answers such a different mission statement.

Media Queries: Navigation Bar Transformations

I recently reviewed Brad Frost’s thoughts on responsive navigation patterns. In terms of mobile widths, I personally have been using the select menu option, utilizing a jQuery script to change out a nav’s unordered list UL for select option tags. I had found it to be a perfect way to utilize a phone’s native function — the act of pulling up the navigation menu a seemingly seamless experience. After reading his cons in that use, I’ve changed my mind.

In a mobile setting, select menu “rolodexes” like in iOS are not a sensible way to display navigation menus because users generally do not know what navigation options there are to begin with. Hence, I agree with him that they are potentially confusing. One must consider the normal, intended use of multiple select menus as a form element that combines many related items. For example in a shopping cart, I want to show color options for a t-shirt. When a user clicks on “select a color”, they expect to find only names of colors like red or blue. In the case of “navigation”, the user might be fairly daunted when presented with many unrelated links in a website. Similarly in my example, someone looking to chose a product color is going to be confused when options like blue hoodies and red jackets appear.

My alternative has usually been the do-nothing approach, essentially restructuring the top nav into a mobile-friendly element. My personal default has usually been a full or half width button with soft gradient, to mimic iOS general styling. The one concern that I have encountered by many clients is that they do prefer the nav to fall at the bottom of each subpage. A jQuery detach/append can certainly do this, but that function is processor intensive and rather clunky with click-happy users. One client was so perturbed that I created an entire mobile version of the site with this layout.

My solution for Urban Bean presents the homepage with just nav and on each page, the nav appears at the bottom.

At the end of the article, Brad linked to an interesting pull down nav solution by Inspect Element which essentially takes a cue from the pull-down-to-update effect by Twitter. I’d call it more of a pull-down-to-reveal since the nav height doesn’t stay anchored atop, rather the page itself pulls down to reveal nav from top to bottom. While the solution is very compelling and presents room for creativity, unfortunately I don’t find the pull down nav to be terribly intuitive. Subducted information from the top of a page tends to imply related content to that page, not to the entire website. Also from a UI perspective, we’re taxing the brain to orient two up-and-down motions. The other motion is iOS Safari’s native inclination to snap the entire browser window when you exceed a page’s maximum scroll.

Facebook introduced the left reveal and it works because natively, iOS apps like to slide progressively right to left. Sliding the current page left to right implies we’ve moved back a step. The home menu is further implied to be a master screen by several important details. First, the menu is generally a dark color and color grades downward, second the current page’s subtle box-shadow floats it atop, and thirdly, the page hasn’t quite moved all the over, implying we’re taking a peek into the master Facebook brain behind everything. A left reveal also lets the thumb do its job of scrolling, only this time for navigation. You could do this with the pull down nav but then you’d be asking the user to track three vertically changing elements all at once. Vertigo would ensue (unless that’s what you want!).

My last observation is that I’ve noticed some designers pushing ridiculously small text scaling for their navigation bars as you move toward smaller screen widths. To keep the horizontal element, they’ll squeeze nav buttons, proportionally might I add, into that 20 to 50 pixel height.

CSS Image Swap from Image Crop

I’m often asked by clients and coding learners how to conceptualize the output of HTML/CSS to front-end. Basically these are first steps to fully understanding what the DOM hierarchy is — or in other words, how the browser interprets the document flow and order.

A client was keen to create a CSS class that would produce a image swap with an image tag in a blog post. He would create two images and insert them into a DIV that would “hide” one. On hover, the other half of the image would appear. He knew such a thing could happen and that two divs would possibly be involved but could not determine how the CSS would do this.

The solution is to put both images into a div, we’ll call swapimage, and assign the second image class swap-target.  Here the HTML5 figure tag can be used in place of the div as it works semantically.

<figure class="swapimage">
<img src="image1.png" alt="First Image." />
<img src="image2.png" class="swap-target" alt="Second Image." />
</figure>

And the CSS:

<style type="text/css">
.swapimage {
 display: block;
 position: relative;
 margin: 0;
 padding: 0;
}
.swap-target {
 position: absolute;
 top: 0;
 left: 0;
 display: none;
z-index: 2;
 }
.swapimage:hover .swap-target {
 display: block; }
</style>

Here swapimage acts as a “container” for the image swap.  Relative position allows the second image to absolutely align “over” the other one (set by z-index).  On swapimage:hover, the target image is set to block.   CSS visibility can be used, but I prefer display in most cases, as the difference being it actually removes the element from the page.

Safari File Upload Hang Up

The HTML Form file input tag has been around for ages but for some reason Safari has had native issues with it since the dawn of the Mac era. I always expect there to be issues that arise in every project but this was certainly was a surprise that put me through the early hours of the night before final client testing.

An Ajax hack is required to force Safari to close the keep alive requests which is better explained by techies at Webkit Bugzilla. The hang effect is basically Safari continuing to show it’s uploading a file and never going anywhere. Sometimes the file will work and go through, especially smaller sizes.

Solutions varied on closing keepalive, telling Safari to move it. Airblade Software offers a good solution which is expanded by this freelancer forum I visited. The script requires Ajax and the forum suggested using the Prototype framework’s Ajax support but that would create conflicts with my existing jQuery code so I grabbed the simple Ajax Request Library by Matt Kruse.  As well, a forum user notes you should call the script before the form, thus document ready is added.

In your body’s form, include onsubmit to the kill function.

<form action="upload.php" enctype="multipart/form-data" method="post" onsubmit="closeKeepAlive();">
<input type="file" name="image" />
<input type="submit" id="upload" name="upload" value="Send " />
</form>

In the head:

<script type="text/javascript" src="js/ajaxrequest.js"></script>
<script type="text/javascript">
/* die safari! */
$(document).ready(function () { 
function closeKeepAlive() {
  if (/AppleWebKit|MSIE/.test(navigator.userAgent)) {
    new Ajax.Request("safari-die.php", { asynchronous:false });	
  }
return true;
}
});
</script>

In the php file

<?php header("connection: close"); ?>