Posts Tagged ‘Code’

Make an OpenLayers Preview from Metadata

Wednesday, October 21st, 2009

My horrific Metadata Navigator hack garnered a lot more interest than I expected, so in addition to patching a couple of bugs some users pointed out (thanks folks!), in the 1.1 release I added an interactive map preview using the onlink metadata element. If your metadata has a WMS link built in, your user will get an interactive map they use to view and identify features. You can of course download and run the latest release, but I’d thought I’d go over what I did here. Big hat tip to GeoServer’s map preview implementation for some of the code.

I decided the default summary page was the most logical place to drop the interactive map if it’s available. So in the summary XSL document, I dropped in this:

<div id="map"></div>
<div id="nodelist">
<em>Click on the map to get feature info</em>
</div>
<script type="text/javascript">
wmsurl = '<xsl:value-of
select="metadata/idinfo/citation/citeinfo/onlink"
disable-output-escaping="yes"/>' ;
map_init(wmsurl);
</script>

Basically we’re setting up a couple of div’s on the page to hold the map and the results table. Then we grab the value of the onlink element (empty of it doesn’t exist) and pass it to a map_init() function back in the main page.

We need to do a couple of things at this point. First, we need to make sure what we got was a valid WMS URL. In the old days ESRI would stick your SDE connection info here. I’m a little lazy on this one – I basically check to see if it’s a valid URL and if it has WMS in it – but it should do the trick.

/**
 * Validate the URL is a URL and contains WMS
 */
function isValidWMSURL(s) {
	var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
	if (regexp.test(s) && s.toUpperCase().match('WMS')) {
		return true;
	}
	else {
		return false;
	}
}

Next we’re going to need a function to pull arguments out of the WMS URL and pass them to OpenLayers. Something like this would do the trick:

/**
 * Get URL args
 */
function gup( name, url )
{
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( url.toLowerCase() );
  if( results == null )
    return "";
  else
    return results[1];
}

So our map_init function, called from our summary XSL, will hit both of those functions and pass the request onto OpenLayers. If it doesn’t find a valid URL, it will hide the DIV’s.

function map_init(wmsurl){
	if (isValidWMSURL(wmsurl)) {
		$("#map").show();
		$("#nodelist").show();
		// Set variables from URL argumemts
		wmsurl = urldecode(wmsurl);
		//main url
		wmsbaseurl = wmsbaseurl = wmsurl.slice(0, wmsurl.indexOf("?"));
		//layername
		layername = gup('layers', wmsurl);
		//bounding box
		bbox = gup("bbox", wmsurl).split(",");
		// projection
		epsg = gup("srs", wmsurl);
		// style
		sld = gup("style", wmsurl);
		// call mapgen
		mapgen(wmsbaseurl,layername,bbox, epsg, sld);

	}
	else {
		$("#map").hide();
		$("#nodelist").hide();
	}
}

Now for the meat and potatoes. We’re going to initialize OpenLayers with arguments for the base WMS URL, the layer name, bounding box, projection, and style sheet. We also register the click event to identify features. Note I made a simple PHP proxy to avoid a XSS-up-yours from the browser.

function mapgen(wmsurl, layername, bbox, epsg, sld) {

	// if this is just a coverage or a group of them, disable a few items,
	// and default to jpeg format
	format = 'image/png';

	var bounds = new OpenLayers.Bounds(
		parseFloat(bbox[0]), parseFloat(bbox[1]),
		parseFloat(bbox[2]), parseFloat(bbox[3])
	);
	var options = {
		controls: [],
		maxExtent: bounds,
		maxResolution: 882.7348803710936,
		projection: epsg,
		units: 'm'
	};
	map = new OpenLayers.Map('map', options);

	// setup single tiled layer
	untiled = new OpenLayers.Layer.WMS(
		layername, wmsurl,
		{
			srs: epsg,
			layers: layername,
			styles: sld,
			format: format
		},
		{singleTile: true, ratio: 1}
	);

	map.addLayers([untiled]);

	// build up all controls
	map.addControl(new OpenLayers.Control.PanZoom());
	map.addControl(new OpenLayers.Control.Navigation());
	map.addControl(new OpenLayers.Control.Scale());
	map.addControl(new OpenLayers.Control.MousePosition());

	map.zoomToExtent(bounds);

	// support GetFeatureInfo
	map.events.register('click', map, function (e) {
		document.getElementById('nodelist').innerHTML = "Loading... please wait...";
		var params = {
			REQUEST: "GetFeatureInfo",
			EXCEPTIONS: "application/vnd.ogc.se_xml",
			BBOX: map.getExtent().toBBOX(),
			X: e.xy.x,
			Y: e.xy.y,
			INFO_FORMAT: 'text/html',
			QUERY_LAYERS: map.layers[0].params.LAYERS,
			FEATURE_COUNT: 50,
			Srs: epsg,
			Layers: layername,
			Styles: '',
			WIDTH: map.size.w,
			HEIGHT: map.size.h,
			format: format};
		$.get("services/ws_wms_query_proxy.php", params, function(data) {
			$("#nodelist").html(data);
			});
		OpenLayers.Event.stop(e);
	});
}

That’s it in a nutshell. Thanks to solid open standards like WMS and the fantastic OpenLayers library it’s a piece of cake.

mn

You can see it working on our running Metadata Navigator. Just click on Jurisdictions under Latest Updates on the left. And of course, feel free to download the code on our Projects page.

Tags:
Posted in Code | No Comments »

Google Chrome Frame Puts Chrome in Internet Explorer

Thursday, September 24th, 2009

oh snap!

oh snap!

In the if-you-can’t-beat-them-shove-a-tube-down-their-throat-and-plant-eggs-in-their-chest department, Google has released Chrome Frame, an open source plugin that drops Chrome’s HTML (WebKit) and JavaScript (V8) engines into IE. Ars has a good summary as usual.

The idea is an IE user stumbles upon your site that has a X-UA-Compatible meta tag in header that tells the Chrome Frame plugin to render the page with Chrome rather than Trident (IE’s engine). For IE users that don’t have it installed, you can load some JavaScript that will prompt the user to install Google Chrome Frame. After installation, the user will view the site (and all subsequent X-UA-Compatible sites) with Chrome. Not only will users get stuff rendered in a standards compliant way, it’ll be much faster (Slashdot reports it as 9.6x faster than IE8, which means it’ll be a bazillion times faster than IE6). And users won’t have to give up their retched IE user interface. Yay!

As a web developer the idea of not having to support IE anymore makes me want to jump for joy, but this creeps me out a little. Some people use IE because their stupid IT department makes them, and they will be savvy enough to see Chrome Frame as a joyous prison break. I have no problem with that. But a lot of people use IE because they don’t know any better. They’re going to see a browser window with words in it they won’t read, click to install just as they would install Flash (the I-don’t-know-any-better IE user will click on anything), and have no idea what happened. Even though what happened is positive, it’s still a little unsettling. It’ll make these users think IE is a lot better than it really is, which isn’t a good thing either. And this will happen for all versions of IE, including 8. While IE8’s web standards compliance still lags behind, it isn’t as awful as it used to be.

Microsoft’s only contribution to the debate so far is that they are afraid it would make IE less secure, which caused more laughter across the web than the time they said IE was secure. Microsoft isn’t above screwing with other browsers either, doing things like dropping Silverlight and .NET Framework Assistant excrement onto my Firefox install. Add that to the fact that they still push out the world’s worst web browser, my empathy for them on this one is pretty low.

For my part, I might stick in the X-UA-Compatible meta tag in my pages so people can take advantage of Google Chrome Frame when they visit my sites if they already installed it, but I don’t think I’ll push the download. I have no problem popping up a “your browser is outdated” message to IE6 users, but I’m not ready to shove a tube down their throats and plant eggs in their chests. At least not yet.

Tags: , ,
Posted in News | No Comments »

Simple Python HTTP Server

Tuesday, September 22nd, 2009

Linux Journal posted a nifty Python trick to quickly share files on your network. It should work anywhere that Python does (i.e. anywhere). Just CD to the directory you want to share and type:

python -m SimpleHTTPServer

Anybody that navigates to http://yourmachine:8000 (the default port) will be able to go mucking through that directory and its sub directories. If you’re like me and have lots of stuff running on 8x ports, you can specify the port number at the end off the command. Note this is a built-in Python library. Python doesn’t have the “Batteries Included” moniker for nothing.

Python has made some noise as a capable web server lately with projects like Tornado, which powers FriendFeed, popping up left and right. I’m curious to see where it all plays out in a year or two. Running a Python web application on top of a Python web server has a certain poetry to it.


Editor’s Note: SimpleHTTPServer was merged under http.server at Python 3.x. But I’ve yet to run across anybody doing much with 3.x.

Tags:
Posted in Code | 1 Comment »

Metadata Navigator

Friday, September 11th, 2009

I’ve been resisting sharing a project here for two reasons. First, it involves metadata. Metadata is absolutely one of the most important and valuable things you can do. Like paying taxes. Second, what I did is such a total and complete hack I’m more than slightly embarrassed by it.

To make a long story short*, we decided we were getting off of ArcIMS’s metadata service. In the ESRI realm, that left us with the Geoportal extension to AGS. Due to cost (under price for the Geoportal extension it gives the dreaded please call your local ESRI sales office  for a quote that will leave you crying for the rest of the day) and the sour taste the ArcIMS metadata service left in our mouth, we ruled that out quickly.

We looked at other options. The strongest contender was GeoNetwork Opensource, which is both really nice and which I’ve never been able to get working quite right. I’ve tried different versions over the years and something is always funny. Part of it might be the fact that ESRI likes to stick things like Required: The citation date is a required field in XML elements reserved for dates. Anyways, nothing was quite what we wanted.

When we looked at what we really needed, it boiled down to two things:

And that was it. We decided if we ever ran into a scenario where we needed WCS Z3950 or the like we’d deal with it then, and editing the metadata via ArcGIS Desktop was preferred by the only person that mattered – the one doing the metadata maintenance.

In 4 – count ‘em, 4 – hours, I put together a site that did just that. I give you that number not to brag, but to lower your expectations/beg for mercy. I spent another hour or two later on adding a RSS feed and some other niceties. But basically all it does is:

You can see it at http://maps.co.mecklenburg.nc.us/metadata. You can grab the source code on the Projects page.

Be ye forewarned: it is a steaming pile of hacks. It’s composed of some JavaScript and some PHP and some dust tape and a whole lot of swearing (whenever I use the word metadata, you can mentally append very important and swearing next to it). It’s doing searches through actual XML files sitting on disk. That alone should get me sent to whatever version of Dante’s easybake you subscribe to. There’s only about 100 lines of JavaScript powering the site itself, and a couple of web services taking requests and shelling out data. The code itself is in the I-got-it-to-work-and-ran-away state.

But darn it, it works. If you’ve got < 500 metadata records, a low traffic metadata site, and no needs beyond what I listed, it works just fine, and I’ve gotten enough inquiries about it to justify tossing it out there, warts and all. If you decide to look at the code though, please just repeat to yourself: Tobin did this in 6 hours, it’s a hack, Tobin did this in 6 hours, it’s a hack, Tobin did this in 6 hours, it’s a hack….

*Short story long: The ArcIMS metadata service has always been a bit of a hack. It’s tricky to get working. It dies a lot. It stores data in its own tables in SDE that don’t really interact with anything else in the ESRI universe. The SDE and ArcIMS versions have to be exactly the same. To upgrade ArcIMS you have to do this funny little import/export command line dance, which without fail you will forget about until after an upgrade. All in all the best thing you can say about ArcIMS’s metadata service is that it occasionally works. One day we decommissioned a test SDE server due to hardware failures, only to realize weeks later it held our ArcIMS metadata, as it was the only SDE server we had at the exact version as the ArcIMS server. Since our new test server is on yet a different SDE version, we had to find an old box, dumping Windows/SQL Server/SDE on it, restoring the database, and mdexport out the data. Since we couldn’t really run this duct-tape SDE server full time, and we didn’t want to have a dedicated SDE server just for this, and we couldn’t upgrade the ArcIMS server for other reasons, we decided it was time to take our ball and go home.

Tags:
Posted in Code | 2 Comments »

jQuery Tools – A Cool New UI Library for jQuery

Wednesday, September 9th, 2009

When I have to do JavaScript programming for a web site, the first thing I do is drop in a reference to jQuery on Google’s CDN. I can’t imagine doing any non-trivial JavaScript work without jQuery. jQuery is:

…a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.

And it does that better than any other library I’ve tried. But none of that describes user interface pieces – tabs, accordions, image sliders, overlay windows, etc. – all the bits and pieces that make for a nice user experience. There are thousands of extensions you can find for these tasks, but having a single UI library makes for compact downloads and for a more consistent experience, both for users and the developer.

I’ve been using jQuery UI for a while now, and will continue to do so in lots of projects. It’s a great library and takes care of a ton of UI pieces, from date pickers to tabs. It has a very good theme roller. The only knock on it is it’s a little on the heavy side.

A little while ago I ran across jQuery Tools, a new UI library for jQuery. It doesn’t have all the bells and whistles of jQuery UI (no slider, date picker, dialog, drag & drop, etc.), but it’s unbelievably tiny. GZIP’d the entire library is less than 6KB, and includes a lot of useful UI pieces – tabs, accordions (a particular tab implementation becomes an accordion), tool tips, overlays, etc. I finally got around to trying it, and I’m glad I did.

Besides being so compact (using tabs, overlay, and expose, the total library size was 2.83KB GZIP’d) and fast, it’s really easy to use. Setting up some tabs or an thickbox style window takes very little code, and the code itself is logical and easy to follow. The documentation is good and they have sample code that covers most scenarios, from basic rendering to call back functions and event handling. Skinning objects is extremely easy, with a number of examples available. For the UI elements it offers I haven’t run across an easier UI library to get started with.

My only nit to pick is it could use some CSS themes – just 4 or 5 different themes/images for all the tools that you can easily access in one place.  Right now you have to hunt and peck for them for each tool (if it’s there and I didn’t find it somebody please clue me in). But that’s a small gripe, and didn’t hold me up at all while coding.

One of the best things you get with jQuery is a very enthusiastic and prolific development community, and jQuery Tools is a prime example. If you’re looking for a lightweight UI kit for jQuery, I recommend giving it a shot.

Tags: ,
Posted in Code | No Comments »