Posted in jQuery | Posted on 06-07-2009 | 2,286 views
Last week I blogged on jQuery UI tabs and Google Maps. That led me to take another look at Yahoo's Maps API. I had worked with this sometime ago when I created my CFYahoo project. The code I wrote for the wrapper though only interfaced with their REST API. This let you get maps as images and save them to your server. This weekend I took a look at the AJAX API.
As you guess, this is a pure JavaScript solution. Include a script tag pointing to their service, create a map object, and you're good to go. In general, it worked well. I was a bit disappointed by their documentation though. Their reference guide spells out all the various methods, but is very slim on actual implementation details. So for example, you can create a YGeoPoint object from a latitude and longitude object, but they don't tell you what the valid values are in that range. I guess I learned that in Geography class 20 years ago, but my memory isn't what it used to be. Another example - they mention the various event handlers you can make use of, but from what I see, they don't specify what gets passed to the event. Nor do they fully explain what each event does. You can guess, of course, but I was surprised one more than one occasion when some code fired an event I didn't expect.
Yet another example (and I don't mean to harp so much on this, but it really bugs me when documentation is lacking, and yes, I know I've not done a great job at this myself) - there are 3 valid map types defined. They are: YAHOO_MAP_SAT, YAHOO_MAP_REG, YAHOO_MAP_HYB. Now I know that you can take a guess at these. Sat is for satellite, hybrid is satellite and regular, but would it have killed Yahoo to simply put a one line description of these fields somewhere in the docs?
Ok, I'll stop now. Once I figured things out and began to play, I decided to have some fun. Check out this template:
2
3<head>
4<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=cfjedimaster"></script>
5<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
6<style type="text/css">
7#map{
8height: 100%;
9width: 100%;
10}
11</style>
12
13<script>
14$(document).ready(function() {
15 // Create a map object
16 var map = new YMap(document.getElementById('map'));
17
18 var mapTypes = map.getMapTypes()
19
20 var validZooms = map.getZoomValidLevels()
21 //remove a few zooms since a lot of places won't let us zoom in
22 for(var i=0;i<5;i++) validZooms.shift()
23 //pop one or two off the top
24 for(var i=0;i<2;i++) validZooms.pop()
25
26
27 //no need for dragging
28 map.disableDragMap()
29
30 // Set map type to either of: YAHOO_MAP_SAT, YAHOO_MAP_HYB, YAHOO_MAP_REG
31 map.setMapType(YAHOO_MAP_REG);
32
33 // Display the map centered on a geocoded location
34 map.drawZoomAndCenter("San Francisco", 10);
35
36 window.setInterval(moveMe,6000)
37
38 function moveMe() {
39 var newLat = Math.floor(Math.random()*181)-90
40 var newLong = Math.floor(Math.random()*361)-180
41 var gp = new YGeoPoint(newLat,newLong)
42 map.panToLatLon(gp)
43 map.setMapType(getRandomType())
44 map.setZoomLevel(getRandomZoom())
45 }
46
47 function getRandomType() {
48 var type = mapTypes[Math.floor(Math.random()*mapTypes.length)]
49 return type
50 }
51
52 function getRandomZoom() {
53 var zoom = validZooms[Math.floor(Math.random()*validZooms.length)]
54 return zoom
55 }
56
57})
58</script>
59</head>
60
61<body>
62
63<div id="map"></div>
64
65</body>
66</html>
This script creates a map object centered on San Francisco. (Sorry, I thought my home town was the center of the universe?) I then fire off an interval to run "moveMe" every 6 seconds. This function picks a random location on the planet, a random map type, and a random zoom level (although note I trim the zoom values at the edges). Basically what you get is a full screen view of the Earth at random locations.
You can see an example of this here (Note - most likely I will go over my usage limit for Yahoo, sorry!): http://www.coldfusionjedi.com/demos/yahoomapsajx/test2.html
Kind of fun, but tends to show ocean more often than not. No surprise there - we live on a planet that is 3/4ths water.
I then began work on a new version. I wanted a version where a map would fade in, instead of loading in blocks. I updated my code to use 2 DIVs. One for an initial map, another for the map that would load the new location. In theory, I could flip back and forth. I used the event handlers to fade out the old map, fade in the new map, and call out again in a few seconds to load a new map. In general it worked ok, but I removed the random zoom since zooming changed the map and forced another 'map loaded' event. I also removed the random map type. (Although you will see some of the code left over.)
2
3<head>
4<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=cfjedimaster"></script>
5<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
6<style type="text/css">
7.map {
8 height: 500px;
9 width: 500px;
10 float:left;
11 display:none;
12}
13
14#status {
15 float:left;
16 padding-left: 20px;
17 font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
18}
19</style>
20
21<script>
22$(document).ready(function() {
23
24 //used for debugging
25 var TEMP = 0
26
27 //flag for m2
28 var m2flag = true
29
30 //size it, since map gets confused by hidden
31 size = new YSize(500,500)
32
33 // Create a map object for each div
34 var map1 = new YMap($("#map1").get(0),YAHOO_MAP_REG,size)
35 var map2 = new YMap($("#map2").get(0),YAHOO_MAP_REG,size)
36
37
38 //Listen for loading
39 YEvent.Capture(map1,EventsList.endMapDraw,mapLoaded)
40 YEvent.Capture(map2,EventsList.endMapDraw,mapLoaded)
41
42 //get data from map1, used for map types and zooms
43 var mapTypes = map1.getMapTypes()
44 var validZooms = map1.getZoomValidLevels()
45
46 //remove a few zooms since a lot of places won't let us zoom in
47 for(var i=0;i<5;i++) validZooms.shift()
48 //pop one or two off the top
49 for(var i=0;i<2;i++) validZooms.pop()
50
51 //no need for dragging
52 map1.disableDragMap()
53 map2.disableDragMap()
54
55 //begin with map1
56 var currentMap = "map1"
57
58 // Display the map centered on a geocoded location
59 map1.drawZoomAndCenter("San Francisco", 10);
60
61 function moveMe(thismap) {
62 console.log('moveMe '+thismap)
63 var newLat = Math.floor(Math.random()*181)-90
64 var newLong = Math.floor(Math.random()*361)-180
65 var gp = new YGeoPoint(newLat,newLong)
66 var mp = eval(thismap)
67 if(m2flag) {
68 mp.drawZoomAndCenter(gp, 10);
69 m2flag = false
70 } else {
71 mp.panToLatLon(gp)
72 //mp.setMapType(getRandomType())
73 }
74 $("#status").html("<p>Moved to "+newLat+" Lat, "+newLong+" Long</p>")
75 }
76
77 function getRandomType() {
78 var type = mapTypes[Math.floor(Math.random()*mapTypes.length)]
79 return type
80 }
81
82 function getRandomZoom() {
83 var zoom = validZooms[Math.floor(Math.random()*validZooms.length)]
84 return zoom
85 }
86
87 function mapLoaded(e) {
88 //console.log('loaded '+currentMap)
89
90 //fade out, fade in
91 if(currentMap == "map1") $("#map2").fadeOut('slow', function() { $("#map1").fadeIn('slow') })
92 else $("#map1").fadeOut('slow', function() { $("#map2").fadeIn('slow') })
93
94 //$("#" + currentMap).fadeIn('slow')
95
96 //call out to move next map
97 if(currentMap == "map1") {
98 nextMap = "map2"
99 currentMap = "map2"
100 } else {
101 currentMap = "map1"
102 }
103 /*
104 TEMP++
105 if(TEMP < 10) window.setTimeout(moveMe,5000,currentMap)
106 else console.log('ABORT')
107 */
108 window.setTimeout(moveMe,5000,currentMap)
109 }
110})
111</script>
112</head>
113
114<body>
115
116<div id="map1" class="map"></div>
117<div id="map2" class="map"></div>
118<div id="status"><p>Starting in San Francisco</p></div>
119</body>
120</html>
You can see this here: http://www.coldfusionjedi.com/demos/yahoomapsajx/test3.html
Like the first example, this one also spends a lot of time out at sea. I then decided to figure out the ranges for American long/lat. This took me a few minutes to get right. I ended up using the Polylines demo, which reported long/lat values for your mouse clicks, and used that to figure out ranges for the continental United States. (If anyone in Hawaii wants me to update this to support your state, please send plane tickets so that I may properly ensure my code is working correctly.) I modified moveMe function like so:
2 //console.log('moveMe '+thismap)
3 //Miami 25, Seattle 47
4 var newLat = Math.floor(Math.random()*22)+25
5 //Seattle 122, Maine 68
6 var newLong = Math.floor(Math.random()*57)+(-124)
7 var gp = new YGeoPoint(newLat,newLong)
8 var mp = eval(thismap)
9 if(m2flag) {
10 mp.drawZoomAndCenter(gp, 10);
11 m2flag = false
12 } else {
13 mp.panToLatLon(gp)
14 }
15 $("#status").html("<p>Moved to "+newLat+" Lat, "+newLong+" Long</p>")
16}
The m2flag code simply handles initializing the second map correctly. I couldn't initialize it and not listen to it so I simply wrote a hack to handle the first time I want to set that map up. You can see this version here: http://www.coldfusionjedi.com/demos/yahoomapsajx/test4.html
As I said, useless, but kind of fun anyway.



check out http://www.openlayers.org/
it's a API for abstracting away all these company api's
so you can be provider independent
try and avoid commercial mapping API's where ever possible
in developing to say yahoo is you can't
just switch over to say VE, Google or openstreet maps, or even your own with something like MapGuide.
It's future proof, plus you can mix and match your mapping services
http://www.openlayers.org/dev/examples/baseLayers....
http://ennoble.dreamhosters.com/mapguide-central/
Jquery is for browsers, like Openlayers is for mapping.
If you have a client who live VE and and you prefer google, why redevelop/port the same stuff each time, when you can develop with openlayers?
I don't get the MVC reference as mapping is rather javascript heavy, porting that is still a pain.
The licensing terms for the commercial providers can be rather restrictive.
Of course it depends on what your doing, simple maps stuff aint such a big deal, but once you start working with them, it can get complex real quick
Again - I just don't see switching providers being something that would happen often.
1. The currently developed solution does not offer the right type of functionality and a new vendor would provide a better fit. (If this is the case then shame on the Project Managers and the Developer for not figuring this out before 1 line of code was written and doing it right the first time)
2. The solution is working fine and then for whatever reason the game is changed, maybe the web service provider tanked and went out of business. (If this happens it is just plain not your fault)
I used to think that I had to be "Object, Object, Object" and "Framework, Framework, Framework" all of the time and what I've come to realize is pretty simple and honest truth for me which is...
Rarely does anyone ever change database vendors on me and I've never gotten anything out of a framework other than a slower version of my original application.
Let me play Sean Corfield and say that this is "Right for Me - you do what you want but this works for Me".
What works for me is using DBX to quickly generate CRUD which I (perish the thought that you might have to actually get off your ass and write something on your own) copy and paste whatever portions of code I want into MY cfc's. I use hints and comments all over the place and I create external documentation as well and I typically plan apps around features and functionality rather than the data model.
@Zac - before you tell me that my code won't easily allow me to yank a solution from SQL Server and move it to ORACLE I will tell you that it's just not worth creating a slow app over and that the apps are documented well enough to allow for quick adjustments to the code to move from one environment to another.
Have at it everyone - tear me apart. While you're doing that and sifting through your hundreds of lines of auto-generated framework code to give you back a record I should have enough time to run to Chase and deposit a few checks, grab a vanilla latte and have a couple of cigarettes. Everyone is so worried about whether or not their app will run right on the Moon, Saturn, Jupiter and the Sun that I would wager that most of their apps never get done.
@Ray - please keep the examples coming. I've learned so much from your site and your books even though they were never cluttered with "and now do this in 20 other ways so that you can be prepared for a whole ton of crap that's not in the spec and will most likely never come to pass".
I believe that we don't need to see all 1000 ways to skin the cat, just 1 or 2 and we can probably figure out the rest for our particular "favorite personal way" of doing things.
I also believe that if someone is nice enough to blog an example and pass down knowledge for free that we probably shouldn't criticize it unless it just flat out doesn't work or is not factual.
Thanks for nothing ;)
[Add Comment] [Subscribe to Comments]