David Janes' Code Weblog

December 11, 2008

A brief survey of Yahoo Pipes as a DQT

demo,djolt,dqt,ideas,semantic web,work · David Janes · 7:19 am ·

MacFUSEYahoo Pipes is a visual editor of mashups, allowing you to take data from sources on the net, transform them in various interesting ways and output the result as Atom, RSS or JSON. The primary downside Pipes of course is that you’re totally dependent on Yahoo for the infrastructure: it runs at Yahoo pulling feeds that have to be accessable through the public Internet.

It’s easy to use Pipes: just go to this page and start working with the sample example Pipe. You’ll need a Yahoo login ID, but most of us have that anyway. I’ve created an example that uses Yahoo Pipes to feed a Djolt template which you can see here.

We can analyze Pipes in the terms of the DQT paradigm we’ve outlined in the previous post.

Data Sources and Queries

Sources and Queries are merged (quite logically) in the Pipes interface. You can read in depth documentation here.

  • Fetch CSV
  • Feed Autodiscovery – outputs syndication feeds found on a page (RSS feeds on a CBC page)
  • Fetch Feed
  • Fetch Page – will read a page and parse the contents with a reg
  • Fetch Site Feed – this is the logical combination of Fetch Feed and Fetch Autodiscovery
  • Flickr – find images by tag near a location (photos of cats in Toronto)
  • Google Base – look up information in Google Base
  • Item Builder – a way of building new items from existing items
  • Yahoo Local
  • Yahoo Search

Transforms

The operator documentation can be read here.

  • Count
  • Filter
  • Location Extractor – a geocoder that magically looks for locations
  • Loop
  • Regex
  • Rename
  • Reverse
  • Sort
  • Split
  • Sub-element – pulls a particular sub-element of an item and makes that the item. This is very much like WORK path manipulation
  • Tail
  • Truncate
  • Union
  • Unique
  • Web Service

Plus a number of specialized data services, for dealing with elements such as dates.

Templates

Pipes does not provide an arbitrary Djolt-like template producing HTML. Instead, they provide a number of pre-made code templates that output well known data types, including RSS, JSON and Atom (and some stranger choices, like PHP).

December 4, 2008

Djolt Indirection

demo,djolt,ideas,python · David Janes · 6:05 am ·

I’ve been working through a sticky problem with Djolt, trying to implement my Toronto Fires example in as few lines as possible. As part of this, I’ve come up with the idea of adding indirection to Djolt templates:

import djolt

d = {
    "a" : "It says: {{ b }}",
    "b" : "Hello, World"
}

t = djolt.Template("""
a: {{ a }}
b: {{ b }}
*a: {{ *a }}
""")

print t.Render(d)
""")

print t.Render(d)

Which yields:

a: It says: {{ b }}
b: Hello, World
*a: It says: Hello, World

This is significantly updated from the original version I posted here an hour ago. The indirection now makes the variable read as a template. This is a much more powerful concept.

November 22, 2008

Toronto Fires

demo,djolt,ideas,maps,work · David Janes · 4:19 pm ·

Here’s a little mashup I’ve been putting together for the last few days: Toronto Fires.

It’s taking the data listed here on the City of Toronto’s Fire Services “Active Accidents”, scraping it (by pretending HTML is XHTML and treating it as WORK objects), geocoding it (using our WORK Google API) and mapping it (using this information).

This is very much a work in progress, but here’s a few more things that are involved:

  • we read body.table.tr.td[1].table.tr[1].td.table.tr as a list to get the rows in the table
  • we map those rows into the Geocoder use a new magic technology we’ll be explaining in the next few days: DjoltDjango-like templates
  • the output program is just one big Djolt template

I’m not quite satisfied with how the current page is constructed: I want the final result to be much more simple.

November 12, 2008

Work API Teaser II – Praized API

demo,ideas,python,search,semantic web,work · David Janes · 6:46 pm ·

Implementing a merchant search using the Praized API took about 10 minutes (mainly finding the right documentation), using my WORK framework:

class PraizedMerchants(bm_api.API):
    """See: http://code.google.com/p/praized/wiki/A_Second_Tutorial_Search"""

    _uri_base = "http://api.praized.com/apitribe/merchants.xml"
    _meta_path = "community"
    _item_path = "merchants.merchant"
    _page_max_path = 'pagination.page_count'
    _page_max = -1

    def __init__(self, api_key, slug = "apitribe", **ad):
        bm_api.API.__init__(self, api_key = api_key, **ad)

        self._uri_base = "http://api.praized.com/%s/merchants.xml" % slug

    def CustomizePageURI(self, page_index):
        if page_index > 1:
            return  "page=%s" % page_index

Partially hardcoding ‘apitribe’ as a ‘community slug’ is probably a bad idea. Anyhoo, here’s how you call it…

api_key = os.environ["PRAIZED_APIKEY"]
api = PraizedMerchants(api_key = api_key, slug = "david-janess-code")
api.SearchOn(
    q = "Bistro",
    l = "Toronto",
)
for item in api.IterItems():
    print json.dumps(item, indent = 1)

… and a set if results, somewhat edited below. I’ll have to figure out what that “permalink” is all about (I’ve edited it to shorten it)  … it could be something neat, but I haven’t quite grasped all the ins and outs of what Praized wants to accomplish as a business.

{
 "@Index": 0,
 "@Page": 1,
 "short_url": "http://przd.com/zAU-7",
 "pid": "af5bebd604f3d1517a8113e0a2e8cc58",
 "updated_at": "2008-10-04T20:49:34Z",
 "phone": "(416) 585-7896",
 "permalink":
   ".../praized/places/ca/ontario/toronto/coffee-supreme-bistro?l=Toronto&q=Bistro",
 "name": "Coffee Supreme Bistro",
 "created_at": "2008-10-04T20:49:34Z",
 "location": {
  "city": {
   "name": "Toronto"
  },
  "country": {
   "code": "CA",
   "name_fr": "Canada",
   "name": "Canada"
  },
  "longitude": "-79.384071",
  "regions": {
   "province": "Ontario"
  },
  "postal_code": "M5J 1T1",
  "latitude": "43.646347",
  "street_address": "40 University Avenue"
 }
}

November 9, 2008

Adding MapField to inputEx

demo,genx,html / javascript,ideas,inputex,maps · David Janes · 7:20 am ·

InputEx is a neat Javascript library by Eric Abouaf and other contributors to dynamically create forms. It’s best shown by example, so:

I’m working on a project called GenX that allows people to dynamically lookup, edit and create data in editors (such as in WordPress). One of the features I want is the ability to add maps so after a week of research, I’ve created a MapField for inputEx:

Notes

  • this is just a preliminary version; there’s probably some code style and idiom issues that need to be worked out
  • I’m going to ask the InputEx group to pick this up; I reserve no rights
  • it’s not fully integrated into the Builder example yet
  • it works with Google Maps, Yahoo Maps and Microsoft’s Virtual Earth. You will need a key for your domain for Google Maps, see the example above about how to insert your key
  • it introduces a concept of a Globals for MapField, as there are certain settings (i.e. your mapping keys) that really belong at “class” level rather than instantiated object level
  • Mapping APIs are dynamically loaded
  • Zoom levels are returned in native format and “universal format
  • I’ve done all my testing of FF3, so there may be browser issues I need to look at

Code changes

  • the only files needed are
    • examples/map_field.html
    • js/fields/MapField.js

Where this is going

  • I’ve spent the last week working on maps; I need to get back to using this code rather than improving and documenting it
  • I want to add a geocoder
  • I want the geocoder to be able to be sensitive to other form fields, so for example if you’re entering an address it can actually use those as an input

One final mod to inputEx

I’ve modified the builder to make the pencil icon more obviously become the close button when you’ve opened a subpanel. You can see the demo here. Here’s the change set:

In images:

curl --location http://www.famfamfam.com/lab/icons/silk/icons/pencil_delete.png \
 > pencil_delete.png

In inputex/inputExBuilder/css/inputExBuilder.css add:

div.inputEx-TypeField-EditButton.opened {
   background-image: url(../../images/pencil_delete.png);
}

In inputex/js/fields/TypeField.js replace onTogglePropertiesPanel with:

   onTogglePropertiesPanel: function() {
      if (this.propertyPanel.style.display == 'none') {
         this.propertyPanel.style.display = '';
         YAHOO.util.Dom.addClass(this.button, "opened");
      } else {
         this.propertyPanel.style.display = 'none';
         YAHOO.util.Dom.removeClass(this.button, "opened");
      }
   },

November 7, 2008

How to use the Google Maps API

demo,html / javascript,maps,tips · David Janes · 6:32 am ·

The Google Maps API is the great granddaddy of mapping API. Originally, the GMap API was an internal private Google API until reverse engineered by Adrian Holovaty to create the first great mapping mashup, Chicago Crime (now folded into Every Block). The API is well documented, well understood and easy-to-use but suffers from the look getting a little long in the tooth and the API key design imposing a higher administrative burden than the competing packages.

The way we set up the events in Google Maps is a little different than we did in MapQuest, Yahoo Maps and Visual Earth. GMaps uses a two phase creation scheme, using one call to create the map object and a second call to actually display it somewhere. I like this and it would have got around the “jumping map” issue we saw in Virtual Earth. Because we want to capture the load event – to get the initial state of the map – we have to put it between these two calls otherwise we’ll miss the load event (it would be nice if Google just called your “onload” callback if the map was already loaded).

My least favorite part of the GMap API is that you need a per-domain API key. This is the most restrictive licensing of any of the mapping packages. Amongst the problems this will cause you:

  • if you’re working in development, staging, deployment environments you’ll have to drive your map from dynamic HTML, as you’ll need to switch in the correct key
  • http://user.example.com, it will mean that all your users will have to individually sign up for API keys — e.g. uptake will be slow. update: see the comments

The documentation for the GMap API is by far the best of any of the mapping package. Everything is cleanly laid out and there’s no question how you get from concepts, to examples, to the API spec.

Here’s our example map application and the source below. You’ll have to get your own API key and substitute it in if you want to start using this example. Geocoding is almost as easy as in the Yahoo API, with the caveat that you really want to set the baseCountryCode, as it won’t make a guess for the country on your behalf. Unlike all the other applications, the GMap API will not take strings where it expects numbers, hence all the parseFloats in the example below.

<html>
<head><script
    type="text/javascript"
    src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURKEY"></script>
<style type="text/css">
#id_map {
    height: 75%;
    width: 100%;
}
</style>
</head>
<body>
<div id="id_map"></div>
<p>
Lat: <input type="text" id="id_lat" onchange="map_js.onupdate_ll()" />
Lon: <input type="text" id="id_lon" onchange="map_js.onupdate_ll()" />
Zoom: <input type="text" id="id_zoom" onchange="map_js.onupdate_zoom()" />
</p>
<script type="text/javascript">
map_js = {
    e_lat : null,
    e_lon : null,
    e_map : null,
    g_map : null,
    g_geocoder : null,

    create : function() {
        map_js.e_map = document.getElementById("id_map");
        map_js.e_lat = document.getElementById("id_lat");
        map_js.e_lon = document.getElementById("id_lon");
        map_js.e_zoom = document.getElementById("id_zoom");

        map_js.g_map = new GMap2(map_js.e_map);
        map_js.g_geocoder = new GClientGeocoder();
        map_js.g_geocoder.setBaseCountryCode("ca")

        GEvent.addListener(map_js.g_map, "load", map_js.onposition);
        GEvent.addListener(map_js.g_map, "moveend", map_js.onposition);
        GEvent.addListener(map_js.g_map, "zoomend", map_js.onposition);

        map_js.g_map.addControl(new GSmallMapControl());
        map_js.g_map.addControl(new GMapTypeControl());

        map_js.g_geocoder.getLatLng("Toronto, ON", map_js.ongeocoded);
        // map_js.g_map.setCenter(new GLatLng(43.648565, -79.385329), 13);
    },

    ongeocoded : function(point) {
        if (!point) {
            alert("not found");
        } else {
            map_js.g_map.setCenter(point, 13);
        }
    },

    onposition : function() {
        var c = map_js.g_map.getCenter();
        map_js.e_lat.value = c.lat();
        map_js.e_lon.value = c.lng();

        var z = map_js.g_map.getZoom();
        map_js.e_zoom.value = z;
    },

    onupdate_ll : function() {
        map_js.g_map.panTo(
            new GLatLng(parseFloat(map_js.e_lat.value), parseFloat(map_js.e_lon.value)));
    },

    onupdate_zoom : function() {
        map_js.g_map.setZoom(parseInt(map_js.e_zoom.value));
    },

    end : 0
};
map_js.create();
</script>

November 5, 2008

How to use the Microsoft Virtual Earth API

demo,html / javascript,maps,tips · David Janes · 1:40 pm ·

Next up in our tour of Javascript mapping APIs is Microsoft’s Virtual Earth. VE is a full-featured mapping API with a visually appealing look, but with a number of gotchas what watchfors which I’ll list here.

VE is rather picky about the CSS and styles it sees (not nearly so much as MapQuest though!). In particular:

  • make sure you add a position: relative or position: absolute to the CSS definitions for the map’s DIV, otherwise it will go crazy on at least Firefox. I added position: relative and it worked fine
  • contrary to the documentation, VE wants to see the style rules directly on the element rather than inherited from CSS, otherwise it seems to default to the 600px by 400px default. Fortunately, once you’ve done this it does understand width: 100% and similar.

Unlike MapQuest and Yahoo Maps, VE comes with a rather comprehensive map control installed. The downside of this is that if you want a simpler interface you’re going to have to code it yourself. In particular, there’s an option for a “Bird’s Eye” view of the map you’re looking at. Once you click on this, concepts like the map having a latitude and longitude go out the window (for reasons I don’t grasp). You can see in the example below that we actually test to see if Lat/Lon is available before attempting to display it. Also note that the documentation for VEMap.GetCenter is wrong — a null is not returned; instead Latitude and Longitude are null.

Microsoft really needs to adopt a more modern view of Javascript. One obvious thing would be to start using namespaces to isolate code — use VE.Map rather than VEMap. The VEMap constructor doesn’t accept a (DOM) element as an argument, you have to pass the ID. Another ugliness is the use of lengthy optional argument lists, such as this atrocity:

VEMap.Find(what, where, findType, shapeLayer, startIndex,
  numberOfResults, showResults, createResults, useDefaultDisambiguation,
  setBestMapView, callback);

This was understandable in the Win32 C-code days but not so much when passing a dictionary would accomplish much of the same in a simpler manner.

VE includes a rather straightforward geocoding call – despite what the documentation above implies. Just do:

map_js.ve_map.Find(null, "Toronto, ON");

Unfortunately, this has a two shortcomings:

  • you cannot “Geocode at setup time” like you can in Yahoo Maps, so you have to display one location, then jump to the one you really want
  • the Geocoder changes you’re zoom level, whether you want it to or not. From a mapping point-of-view I could see how this makes sense (e.g. show all of Toronto), but it would be nice if it was optional

We’ve got the geocoder in the example below commented out, but you may find it useful. Just remember that it’s asynchronous, so the actual map jump will not happen until after your current JS terminates.

Finally, to end on high note, VE doesn’t appear to need a developer or application key meaning you can just take this example to modify and run as you please. Here’s our example map application and the source below:

<html>
<head>
<script charset="UTF-8" type="text/javascript"
  src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"></script>
<style type="text/css">
#id_map{
position: relative;
}
</style>
</head>
<body>
<div id="id_map" style="width: 100%; height: 75%;">&nbsp;</div>
<br />
<p>
Lat: <input type="text" id="id_lat" onchange="map_js.onupdate_ll()" />
Lon: <input type="text" id="id_lon" onchange="map_js.onupdate_ll()" />
Zoom: <input type="text" id="id_zoom" onchange="map_js.onupdate_zoom()" />

</p>
<script type="text/javascript">
map_js = {
	e_lat : null,
	e_lon : null,
	e_map : null,
	ve_map : null,

	create : function() {
		map_js.e_lat = document.getElementById("id_lat");
		map_js.e_lon = document.getElementById("id_lon");
		map_js.e_zoom = document.getElementById("id_zoom");

		map_js.ve_map = new VEMap("id_map");
		map_js.ve_map.LoadMap(new VELatLong(43.648565, -79.385329), 13,
		  VEMapStyle.Road, false, VEMapMode.Mode2D, true, 1);
		// map_js.ve_map.Find(null, "Toronto, ON");

		map_js.ve_map.AttachEvent("onendzoom", map_js.onposition);
		map_js.ve_map.AttachEvent("onendpan", map_js.onposition);

		map_js.onposition();
	},

	onposition : function() {
		var c = map_js.ve_map.GetCenter();
		if (!c || !c.Latitude) {
			return;
		}

		map_js.e_lat.value = c.Latitude;
		map_js.e_lon.value = c.Longitude;

		var z = map_js.ve_map.GetZoomLevel();
		map_js.e_zoom.value = z;
	},

	onupdate_ll : function() {
		map_js.ve_map.PanToLatLong(new VELatLong(map_js.e_lat.value, map_js.e_lon.value));
	},

	onupdate_zoom : function() {
		map_js.ve_map.SetZoomLevel(map_js.e_zoom.value);
	},

	end : 0
};
map_js.create();
</script>
</body>
</html>

Tip – how to get your browser's User Agent

demo,html / javascript,ideas,tips · David Janes · 10:16 am ·

Every browser normally sends a User-Agent header in its HTTP request. You can use this header to determine what browser and version a website is using, i.e. Internet Explorer, Firefox, whether it’s a mobile browser, an iPhone, etc..

So, what’s your browser’s User-Agent? Just type this in the address bar:

javascript:alert(navigator.userAgent)

Source

November 4, 2008

How to use the MapQuest API

demo,html / javascript,maps,tips · David Janes · 8:02 am ·

This post should be subtitled “MapQuest, I’m disappointed in you”. I have to say I was looking for a lot more out of this toolkit, because they’re a late entrant to the modern AJAX-y map interface so they should have known what will work and what would; because they’re still (I think) the #1 online mapping company;  because I like cheering for scrappy underdog even if they’re really giant behemoths; and finally because I saw Kevin Survance, CTO of MapQuest speak at the Ajax Experience in Boston in 2007 and thought his presentation rocked.

Alas, there’s a number of shortcomings you should know about before you throw away your Google Maps (Yahoo Maps, Live Maps) application:

  • the maps don’t look that great – there’s a lot pixelation due to light or non-existent anti-aliasing
  • the map size has to be set explicitly as a style tag using pixels, not percentages! No CSS for you!
  • the Geocoding feature requires a local proxy – while I understand the technical appeal of this, all the other mapping packages have got around this, why can’t MapQuest? As a result, our example app below does not demonstrate geocoding, it just hard-codes the lat/lon
  • I wasn’t that impressed with the documentation / “hello world”-type examples. One issue here is that MapQuest may be targeting desktop applications and so browser JS is suffering for attention

Now, there seems to be a fairly complete API so there may be further virtues to the MapQuest API that I’m missing, so take that as a caveat. On the other hand, there’s a level of equivalency in map dimensions between all the other mapping packages that MapQuest doesn’t have; I’ll quantify this after I complete this survey of map APIs.

I’ve created an example map application which displays a map, the current lat/lon and zoom level, and lets the map position to be adjusted by editing those same values. If you’d like to get started with the MapQuest API yourself:

  • register with MapQuest to get developer keys, etc.. Note that the examples here is using the default MapQuest key and seem to work fine for testing; I just wouldn’t use that for production purposes
  • copy the code below to “map.html” in favorite hosting environment — it should even work off your disk
  • add your developer key, if you got one, in the appropriate place
  • run, enjoy, modify

Further reading:

Source (note the script src has been split for formatting purposes):

<html>
<head>
<script src="http://btilelog.access.mapquest.com/tilelog/transaction?transaction=script&
key=mjtd%7Clu6t2h07n1%2C2x%3Do5-lw7l9&itk=true&v=5.3.s&ipkg=controls1,traffic&ipr=false"
    type="text/javascript"></script>
</head>
<body>
<div id="id_map" style="width: 1024px; height: 400px;"></div>
<p>
Lat: <input type="text" id="id_lat" onchange="map_js.onupdate_ll()" />
Lon: <input type="text" id="id_lon" onchange="map_js.onupdate_ll()" />
Zoom: <input type="text" id="id_zoom" onchange="map_js.onupdate_zoom()" />
</p>
<script type="text/javascript">
map_js = {
    e_lat : null,
    e_lon : null,
    e_map : null,
    mq_map : null,

    create : function() {
        map_js.e_map = document.getElementById('id_map');
        map_js.e_lat = document.getElementById("id_lat");
        map_js.e_lon = document.getElementById("id_lon");
        map_js.e_zoom = document.getElementById("id_zoom");

        map_js.mq_map = new MQA.TileMap(map_js.e_map, 9,
             new MQA.LatLng(43.648565, -79.385329), "map");
        map_js.mq_map.addControl(new MQA.ZoomControl());
        map_js.mq_map.addControl(new MQA.ViewControl());

        MQA.EventManager.addListener(map_js.mq_map, "zoomend", map_js.onposition);
        MQA.EventManager.addListener(map_js.mq_map, "dragend", map_js.onposition);

        map_js.onposition();
    },

    onposition : function() {
        var c = map_js.mq_map.getCenter();
        map_js.e_lat.value = c.getLatitude();
        map_js.e_lon.value = c.getLongitude();

        var z = map_js.mq_map.getZoomLevel();
        map_js.e_zoom.value = z;
    },

    onupdate_ll : function() {
        map_js.mq_map.panToLatLng(new MQA.LatLng(map_js.e_lat.value, map_js.e_lon.value));
    },

    onupdate_zoom : function() {
        map_js.mq_map.setZoomLevel(map_js.e_zoom.value);
    },

    end : 0
};
map_js.create();
</script>
</body>

November 2, 2008

How to use the Yahoo Maps Service AJAX API

demo,html / javascript,maps,tips · David Janes · 8:02 am ·

Yahoo is a nice alternative service to Google Maps for displaying maps on your website or service. Amongst its benefits:

  • it’s super easy to set up, as we’ll show below
  • it requires an “application key”, but once you have this you can run on any domain. GMaps requires a per-domain key, which means that if your deploying to multiple domains — for example, if you have a http://user.example.com type site — you’re suddenly going to find yourself with an intractable problem
  • it plays moderately well with YUI conceptually, though it doesn’t seem to use the same code base. UPDATE: you have to do hacks to work with YUI. Sigh.

Note that Yahoo provides several APIs for maps, the AJAX API we’re using here, an API for Flash/Actionscript and a REST API for getting map images. There all different, so make sure you’re not reading the wrong docs for what you’re doing.

I’ve created an example map application which displays a map, the current lat/lon and zoom level, and lets the map position to be adjusted by editing those same values. If you’d like to get started with the Yahoo AJAX maps API:

  • get an application key – do not reuse mine or anyone else’s please
  • copy the code below to “map.html” in favorite hosting environment — it should even work off your disk
  • add your application key in the appropriate place
  • run, enjoy, modify

Further reading:

Source:

<html>
<head>
<script type="text/javascript"
src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=YOURAPPID"></script>
<style type="text/css">
#map{
height: 75%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<p>
Lat: <input type="text" id="id_lat" onchange="map_js.onupdate_ll()" />
Lon: <input type="text" id="id_lon" onchange="map_js.onupdate_ll()" />
Zoom: <input type="text" id="id_zoom" onchange="map_js.onupdate_zoom()" />
</p>
<script type="text/javascript">
map_js = {
    e_lat : null,
    e_lon : null,
    e_map : null,
    y_map : null,

    create : function() {
        map_js.e_map = document.getElementById('map');
        map_js.e_lat = document.getElementById("id_lat");
        map_js.e_lon = document.getElementById("id_lon");
        map_js.e_zoom = document.getElementById("id_zoom");

        map_js.y_map = new YMap(map_js.e_map);
        map_js.y_map.addTypeControl();
        map_js.y_map.addZoomLong();
        map_js.y_map.addPanControl();
        map_js.y_map.setMapType(YAHOO_MAP_REG);

        YEvent.Capture(map_js.y_map, EventsList.endMapDraw, map_js.onposition);
        YEvent.Capture(map_js.y_map, EventsList.changeZoom, map_js.onposition);
        YEvent.Capture(map_js.y_map, EventsList.endPan, map_js.onposition);

        map_js.y_map.drawZoomAndCenter("Toronto, ON", 5);
    },

    onposition : function() {
        var c = map_js.y_map.getCenterLatLon();
        map_js.e_lat.value = c.Lat;
        map_js.e_lon.value = c.Lon;

        var z = map_js.y_map.getZoomLevel();
        map_js.e_zoom.value = z;
    },

    onupdate_ll : function() {
        map_js.y_map.panToLatLon(new YGeoPoint(map_js.e_lat.value, map_js.e_lon.value));
    },

    onupdate_zoom : function() {
        map_js.y_map.setZoomLevel(map_js.e_zoom.value);
    },

    end : 0
};
map_js.create();
</script>
</body>
</html>

« Newer Posts · Older Posts »

Powered by WordPress