{"id":72,"date":"2007-05-11T11:06:29","date_gmt":"2007-05-11T15:06:29","guid":{"rendered":"http:\/\/historicalwebber.mossiso.com\/archives\/72"},"modified":"2010-10-09T22:26:27","modified_gmt":"2010-10-10T02:26:27","slug":"how-does-the-yahooflash-map-work","status":"publish","type":"post","link":"https:\/\/mossiso.com\/2007\/05\/11\/how-does-the-yahooflash-map-work\/","title":{"rendered":"How does the yahoo\/flash map work\u2026"},"content":{"rendered":"<p>There&#8217;s a lot of tutorials out there, but here&#8217;s how I got it to work.<\/p>\n<h2>The Plan<\/h2>\n<p>Got what? Oh, well, basically it&#8217;s being able to use yahoo maps, flash, xml, php, mysql, and data to display a bunch of markers on a map. Each marker contains data pulled from the database, and has a link to a page that displays the full information. For now, I just made a display page. But sometime latter, it will be implemented into the fine <a title=\"Omeka\" target=\"_blank\" href=\"http:\/\/omeka.org\">Omeka<\/a> install that the 1989 project will use.<\/p>\n<h2>The Steps<\/h2>\n<p>Here&#8217;s an outline of what I did.<\/p>\n<ol>\n<li>Create a flash file using the yahoo flash map api component. Available at <a title=\"Yahoo Maps AS-Flash API Components\" target=\"_blank\" href=\"http:\/\/developer.yahoo.com\/maps\/flash\/componentEULA.html\">Yahoo<\/a>.<\/li>\n<li>Add some ActionScript to the first frame that will import data from an xml file.<\/li>\n<li>Create a php page that pulls in data from a MySQL database and displays as an xml file.<\/li>\n<\/ol>\n<h2>Create the swf<\/h2>\n<p>In order to make Yahoo and flash play nicely, you need to install the component linked above. Follow directions there. This will add a new component to your Flash program, available in your components window (Window->Components->Yahoo->com.yahoo.maps.api.flash.YahooMap).<\/p>\n<p>Once that&#8217;s installed, create a new empty fla.  Make a keframe in the first frame on layer one. Drag the yahooMap component onto your stage.<\/p>\n<p>Next, add another layer for your actionscript.<\/p>\n<h2>the ActionScript<\/h2>\n<p>Here&#8217;s the tricky part.  Here&#8217;s the code I used, heavily commented:<\/p>\n<p>[code lang=&#8221;Actionscript&#8221;]<br \/>\n\/*********************************<br \/>\n*  File: yahoomap.as<br \/>\n*  Author: Ammon Shepherd<br \/>\n*  based off of many tutorials and code snippets, mostly from Yahoo! documentation.<br \/>\n********************************\/<br \/>\n\/\/Set the URL where the xml file is.<br \/>\nvar xmlURL = &#8220;http:\/\/chnm.gmu.edu\/1989\/maps\/xml.php&#8221;;<\/p>\n<p>\/\/Import Yahoo map tools<br \/>\nimport com.yahoo.maps.LatLon;<br \/>\nimport com.yahoo.maps.markers.CustomPOIMarker;<br \/>\nimport com.yahoo.maps.tools.PanTool;<br \/>\nimport com.yahoo.maps.widgets.*;<\/p>\n<p>\/\/Create a listener associated with the instance of the Yahoo map component.<br \/>\n\/\/  Set the map to pull down the yahoo map and get the setting\/changes from<br \/>\n\/\/  the onMap function.<br \/>\neuroMap.addEventListener(com.yahoo.maps.api.flash.YahooMap.EVENT_INITIALIZE, onMap);<\/p>\n<p>\/\/This will add a zoom tool and set it as closed by default<br \/>\nvar zoomer:NavigatorWidget = new NavigatorWidget(&#8220;closed&#8221;);<\/p>\n<p>\/\/The onMap function adds the tools, settings, and markers to the map.<br \/>\nfunction onMap(eventData) {<br \/>\n    \/\/create a new PanTool and name it pantool<br \/>\n    var pantool:PanTool = new PanTool();<\/p>\n<p>    \/\/tell the instance of the map to use the new PanTool called pantool<br \/>\n    euroMap.addTool(pantool, true);<\/p>\n<p>    \/\/Add the Navigator widget<br \/>\n    euroMap.addWidget(zoomer);<\/p>\n<p>    \/\/Create a variable called xmlData of the type XML<br \/>\n    var locations_xml:XML = new XML();<\/p>\n<p>    \/\/igore white space<br \/>\n    locations_xml.ignoreWhite = true;<\/p>\n<p>    \/\/when the xml file is loaded, do the fuction within<br \/>\n    locations_xml.onLoad = function(success){<br \/>\n        \/\/if the xml file loaded successfully run the function addMarkers<br \/>\n        if (success) addMarkers(this);<br \/>\n    };<\/p>\n<p>    \/\/then actually load the xml file.<br \/>\n    locations_xml.load(xmlURL);<\/p>\n<p>    \/*******************************************<br \/>\n    * Used this for testing, you don&#8217;t really need it. I was thinking of using<br \/>\n    *   this in the future to display the lat and long to the user.<br \/>\n    \/\/Get the center of the map and store them in the variable called points.<br \/>\n    var points = euroMap.getCenter();<br \/>\n    \/\/trace(&#8220;before convert&#8221; + points);<br \/>\n    \/\/swap the points, so long->long and lat->lat<br \/>\n    convert(points);<br \/>\n    \/\/trace(points);<br \/>\n    ******************************************\/<\/p>\n<p>}<\/p>\n<p>\/\/This is the function that adds the markers to the map.<br \/>\nfunction addMarkers(xml:XML):Void {<br \/>\n    \/\/the addresses variable holds the path to the right xml element.<br \/>\n    \/\/firstChild is the <locations> and childNodes is an array of the <location \/> tags<br \/>\n    var addresses = xml.firstChild.childNodes;<\/p>\n<p>    for(var i=0; i<addresses .length; i++){ \/\/loop through the xml data\n        \/\/address grabs the next child. so as the for loop reiterates, it grabs the\n        \/\/  first <location \/> then the second and so on for all of them.<br \/>\n        address = addresses[i];<\/p>\n<p>        \/***************************************************************<br \/>\n        * MarkerData is the object that holds the info for each marker.<br \/>\n        *   index: is the text that shows up on the marker (usually just A or<br \/>\n        *       what have you. you could use the variable i to show an<br \/>\n        *       incremented number (each marker has it&#8217;s own number).<br \/>\n        *   title: sets the title of the marker and corresponds to the title<br \/>\n        *       parameter in the location tags in the xml file.<br \/>\n        *   description: is the larger text. It corresponds with the description<br \/>\n        *       parameter in the location tag in the xml field.<br \/>\n        *   markerColor: sets the color of the marker, duh \ud83d\ude42 It&#8217;s the border<br \/>\n        *       color, and the color when not expanded.<br \/>\n        *   strokeColor: is the background.<br \/>\n        ***************************************************************\/<br \/>\n        var MarkerData:Object = {index: &#8216;\\&#8217;89&#8217;, title:address.attributes.info, description:address.attributes.description, markerColor:0xcc0000, strokeColor:0xceccc7};<\/p>\n<p>        \/****************************************************************<br \/>\n        *   This actually adds the address to the map using the custom point of<br \/>\n        *       interest style of marker (you can use your own style if you like.<br \/>\n        *       the address.attributes.loc grabs the latitude and longitude from<br \/>\n        *       the loc=&#8221;&#8221; part of the location tag in the xml file. MarkerData<br \/>\n        *       is the stuff we just set above.<br \/>\n        ****************************************************************\/<br \/>\n        euroMap.addMarkerByAddress(CustomPOIMarker, address.attributes.loc, MarkerData);<br \/>\n    }<br \/>\n}<br \/>\n[\/code]<br \/>\n<a href=\"http:\/\/historicalwebber.mossiso.com\/code\/yahoomap.as\">Download yahoomap.as<\/a><\/p>\n<p>(Special thanks to <a href=\"http:\/\/blog.hackerforhire.org\/2007\/03\/16\/code-snippet-20\/\">CodeSnippet<\/a> for providing a way to show code. This was the 5th one I tried that finally worked.)<\/p>\n<h2>The PHP\/XML<\/h2>\n<p>Next we need an xml file. I need to pull the data from a database, so I used a php script which pretends to be an xml file. The basics of that is to put this in the php file:<br \/>\n[code lang=&#8221;php&#8221;]<br \/>\n\/\/ Date in the past<br \/>\nheader(&#8220;Expires: Mon, 26 Jul 1997 05:00:00 GMT&#8221;);<br \/>\n\/\/ always modified<br \/>\nheader(&#8220;Last-Modified: &#8221; . gmdate(&#8220;D, d M Y H:i:s&#8221;) . &#8221; GMT&#8221;);<br \/>\n\/\/ HTTP\/1.1<br \/>\nheader(&#8220;Cache-Control: no-store, no-cache, must-revalidate&#8221;);<br \/>\nheader(&#8220;Cache-Control: post-check=0, pre-check=0&#8221;, false);<br \/>\n\/\/ HTTP\/1.0<br \/>\nheader(&#8220;Pragma: no-cache&#8221;);<br \/>\n\/\/XML Header<br \/>\nheader(&#8220;content-type:text\/xml&#8221;);<br \/>\n[\/code]<\/p>\n<p>Then, because our database doesn&#8217;t store the geocodes by default yet, nor do the items have any type of specific address or what not associated with them, I created an array with specific places and their lat, long. Each of the items in the database have tags associated with them. The array corresponds to tags that have countries names on them. This poses a problem if the tag name is changed, but for now it works OK.<\/p>\n<p>[code lang=&#8221;php&#8221;]<br \/>\n$countries = array(<br \/>\n    array(&#8220;Poland&#8221;, &#8220;52.1874047455997&#8221;, &#8220;19.072265625&#8221;),<br \/>\n    array(&#8220;East Germany&#8221;, &#8220;52.517474393230245&#8221;, &#8220;13.41156005859375&#8221;),<br \/>\n    array(&#8220;Czechoslovakia&#8221;, &#8220;49.210420445650286&#8221;, &#8220;17.490234375&#8221;),<br \/>\n    array(&#8220;Hungary&#8221;, &#8220;47.45780853075031&#8221;, &#8220;19.05029296875&#8221;),<br \/>\n    array(&#8220;romania&#8221;, &#8220;45.98169518512228&#8221;, &#8220;25.07080078125&#8221;),<br \/>\n    array(&#8220;Yugoslavia&#8221;, &#8220;44.26093725039923&#8221;, &#8220;18.96240234375&#8221;),<br \/>\n    array(&#8220;Bulgaria&#8221;, &#8220;42.601619944327965&#8221;, &#8220;25.24658203125&#8221;),<br \/>\n    array(&#8220;Soviet Union&#8221;, &#8220;55.70235509327093&#8221;, &#8220;37.79296875&#8221;)<br \/>\n);<br \/>\n[\/code]<\/p>\n<p>The problem I ran into next was that there were over 15 markers that would share the same lat an long. This makes it hard to click on a marker when it&#8217;s buried under 20 other markers. So at first I tried just adding a couple of digits to the lat and long as it looped through the array. This led to a long line of markers, and didn&#8217;t look very good. Random numbers to the rescue! To create a clustering affect I generated two random numbers, one for the lat and one for the long. This number was added  giving the markers a clustered appearance. Here&#8217;s that part of the code:<\/p>\n<p>[code lang=&#8221;php&#8221;]<br \/>\necho &#8220;< ?xml version='1.0' ?><br \/>\n            <\/locations><locations><br \/>\n            &#8220;;<\/p>\n<p>for($g=0; $g<count ($countries); $g++){\n    $query = mysql_query(\"SELECT i.item_id, i.item_title, i.item_description FROM items i JOIN items_tags it WHERE i.item_id=it.item_id AND it.tag_id = (SELECT tag_id FROM tags WHERE tag_name = '\".$countries[$g][0].\"') LIMIT $limit\");\n    while($result = mysql_fetch_array($query)){\n        $x = rand(10,100)\/100;\n        $y = rand(20,100)\/100;\n        $lat = $countries[$g][1]+($x);\n        $lon = $countries[$g][2]+($y);\n        echo '\n                <location loc=\"'.$lat.', '.$lon.'\" info=\"'.htmlentities($result['item_title'], ENT_QUOTES).'\" description=\"'.description($result['item_id'], $result['item_description']).'\" \/>&#8216;;<\/p>\n<p>    }<br \/>\n}<\/p>\n<p>echo &#8216;<br \/>\n            <\/locations>&#8216;;<br \/>\n[\/code]<\/p>\n<p>You may notice my call to the description function (which, in turn, calls a function called truncate, but you wouldn&#8217;t know that yet). This simply turns all HTML characters into their HTML entity characters. HTML in an XML file will break the XML file&#8230; more specifically the < and \" ' characters. The truncate function I grabbed from php.net's comments for <a href=\"http:\/\/us.php.net\/manual\/ro\/function.substr-replace.php#74024\">substr_replace.  The truncate function shortens long text to a set number of words, and adds an ellipse at the end to signify more text. Here are those two functions:<\/p>\n<p>[code lang=&#8221;php&#8221;]<br \/>\nfunction description($id,$text){<br \/>\n    $description = wordwrap(htmlentities(truncate($text,200), ENT_QUOTES),30);<\/p>\n<p>    $fulltext = $description.&#8221;\\n&lt;a target=&#8217;_blank&#8217; href=&#8217;http:\/\/chnm.gmu.edu\/1989\/maps\/results.php?id=$id&#8217;>Show item&lt;\/a>&#8221;;<\/p>\n<p>    return $fulltext;<br \/>\n}<\/p>\n<p>function truncate($text,$numb) {<br \/>\n    \/\/ source: www.kigoobe.com, please keep this if you are using the function<br \/>\n    \/\/$text = html_entity_decode($text, ENT_QUOTES);<br \/>\n    if (strlen($text) > $numb) {<br \/>\n        $text = substr($text, 0, $numb);<br \/>\n        $text = substr($text,0,strrpos($text,&#8221; &#8220;));<br \/>\n        $etc = &#8221; &#8230;&#8221;;<br \/>\n        $text = $text.$etc;<br \/>\n    }<br \/>\n    \/\/$text = htmlentities($text, ENT_QUOTES);<br \/>\n    return $text;<br \/>\n}<br \/>\n[\/code]<\/p>\n<p>Here&#8217;s the <a href=\"http:\/\/historicalwebber.mossiso.com\/code\/xml.phps\">whole php file<\/a>.<br \/>\nThat basically does it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There&#8217;s a lot of tutorials out there, but here&#8217;s how I got it to work. The Plan Got what? Oh, well, basically it&#8217;s being able to use yahoo maps, flash, xml, php, mysql, and data to display a bunch of markers on a map. Each marker contains data pulled from the database, and has a &hellip; <a href=\"https:\/\/mossiso.com\/2007\/05\/11\/how-does-the-yahooflash-map-work\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">How does the yahoo\/flash map work\u2026<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[3,8,167],"tags":[87,51,60],"class_list":["post-72","post","type-post","status-publish","format-standard","hentry","category-coding","category-school-work","category-technical","tag-digital-maps","tag-history-of-1989","tag-maps"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9wosP-1a","_links":{"self":[{"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/posts\/72"}],"collection":[{"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/comments?post=72"}],"version-history":[{"count":3,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/posts\/72\/revisions"}],"predecessor-version":[{"id":739,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/posts\/72\/revisions\/739"}],"wp:attachment":[{"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/media?parent=72"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/categories?post=72"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mossiso.com\/wp-json\/wp\/v2\/tags?post=72"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}