Merge remote-tracking branch 'tschaub/utfgrid' into utfgrid

This commit is contained in:
mperry
2012-02-25 17:58:51 -08:00
5 changed files with 188 additions and 218 deletions
+50 -54
View File
@@ -1,23 +1,31 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<title> OpenLayers UTFGrid Demo </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src='./OpenLayers.js' type='text/javascript'></script> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>OpenLayers UTFGrid Demo</title>
<link rel="stylesheet" href="style.css" type="text/css">
<script src="../lib/OpenLayers.js"></script>
<style> <style>
#themap { width:512px; height:380px; border:1px black solid; } #attrsdiv {
#attrsdiv { width: 300px; height: 100px; float:right; border: 1px grey dashed;} float: right;
}
#controlToggle li { list-style: none; } #controlToggle li { list-style: none; }
</style> </style>
</head> </head>
<body> <body>
<h1> OpenLayers UTFGrid Demo </h1> <h1 id="title">OpenLayers UTFGrid Demo</h1>
<div id="top"> <div>
<div> <div id="shortdesc">
<p> This page demonstrates the use of the OpenLayers UTFGrid Controls.
This page demostrates the use of the OpenLayers <a href="http://mapbox.com/mbtiles-spec/utfgrid/">UTFGrid</a> Controls. When the selected event is triggered, the underlying feature attributes are shown on the right.
</p>
</div> </div>
<div id="selector"> <div id="attrsdiv"></div>
<div id="themap" class="smallmap"></div>
<p>
When the selected event is triggered, the underlying feature attributes are shown below.
</p>
<ul id="controlToggle"> <ul id="controlToggle">
<li> <li>
<input type="radio" name="type" value="move" id="moveHandler" <input type="radio" name="type" value="move" id="moveHandler"
@@ -40,12 +48,8 @@
<label for="clickHandlerCustom">Click with custom callback</label> <label for="clickHandlerCustom">Click with custom callback</label>
</li> </li>
</ul> </ul>
</div>
</div> </div>
<div id="attrsdiv"></div> <div id="docs">
<div id="themap">
</div>
<div>
<p><a href="http://mapbox.com/mbtiles-spec/utfgrid/">UTFGrids</a> can be used to <p><a href="http://mapbox.com/mbtiles-spec/utfgrid/">UTFGrids</a> can be used to
output highly optimized feature "hit grids". The UTFGrid encoding scheme encodes output highly optimized feature "hit grids". The UTFGrid encoding scheme encodes
interactivity data for a tile in a space efficient manner. It is designed to be interactivity data for a tile in a space efficient manner. It is designed to be
@@ -63,48 +67,43 @@
/* /*
* Map * Map
*/ */
var map = new OpenLayers.Map('themap', { var map = new OpenLayers.Map({
projection: new OpenLayers.Projection("EPSG:900913"), div: "themap",
units: "m", projection: "EPSG:900913",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
controls: [] // No default controls; no pan zoom for demo controls: [] // No default controls; no pan zoom for demo
}); });
/* /*
* Controls * Controls
*/ */
var callback = function(attributes) { var callback = function(dataLookup) {
if (attributes) { var msg = "";
var msg = "<strong>In 2005, " + attributes.NAME if (dataLookup) {
msg += " had a population of " + attributes.POP2005 + " people.</strong>"; var data;
var element = OpenLayers.Util.getElement('attrsdiv'); for (var idx in dataLookup) {
element.innerHTML = msg; // idx can be used to retrieve layer from map.layers[idx]
return true; data = dataLookup[idx];
} else { msg += "<strong>In 2005, " + data.NAME + " had a population of " +
this.element.innerHTML = ''; data.POP2005 + " people.</strong> ";
return false; }
} }
} document.getElementById("attrsdiv").innerHTML = msg;
};
controls = { var controls = {
'move': new OpenLayers.Control.UTFGrid({ move: new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv', callback: callback,
'handlerMode': 'move' handlerMode: 'move'
}), }),
'hover': new OpenLayers.Control.UTFGrid({ hover: new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv', callback: callback,
'handlerMode': 'hover' handlerMode: 'hover'
}), }),
'click': new OpenLayers.Control.UTFGrid({ click: new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv', callback: callback,
'handlerMode': 'click' handlerMode: 'click'
}), })
'click_callback': new OpenLayers.Control.UTFGrid({ };
'handlerMode': 'click',
'callback': callback
}),
}
var control; var control;
for(var key in controls) { for(var key in controls) {
control = controls[key]; control = controls[key];
@@ -126,11 +125,8 @@
* Layers * Layers
*/ */
var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", var osm = new OpenLayers.Layer.OSM();
"http://vmap0.tiles.osgeo.org/wms/vmap0", map.addLayer(osm);
{layers: 'basic'}
);
map.addLayer(ol_wms);
var grid_layer = new OpenLayers.Layer.UTFGrid( var grid_layer = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer', 'Invisible UTFGrid Layer',
+67 -60
View File
@@ -1,85 +1,95 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<title> OpenLayers Multiple UTFGrid Demo </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src='./OpenLayers.js' type='text/javascript'></script> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>OpenLayers Multiple UTFGrid Demo</title>
<link rel="stylesheet" href="style.css" type="text/css">
<script src="../lib/OpenLayers.js"></script>
<style> <style>
#themap { width:512px; height:380px; border:1px black solid; }
#attrsdiv { width: 300px; height: 100px; float:right; border: 1px grey dashed;}
#controlToggle li { list-style: none; } #controlToggle li { list-style: none; }
</style> </style>
</head> </head>
<body> <body>
<h1> OpenLayers Multiple UTFGrid Demo </h1> <h1 id="title">OpenLayers Multiple UTFGrid Demo</h1>
<div id="top"> <div id="shortdesc">
<div> This page demonstrates the use of the OpenLayers UTFGrid Controls with more than one UTFGrid Layer.
<p>
This page demostrates the use of the OpenLayers <a href="http://mapbox.com/mbtiles-spec/utfgrid/">UTFGrid</a> Controls with <em>more than one UTFGrid Layer</em>.
</p>
</div>
<div id="selector">
<ul id="controlToggle">
<li>
<input type="radio" name="type" value="move_pop" id="moveHandler"
onclick="toggleControl(this);" checked="checked" />
<label for="moveHandler">Move (population)</label>
</li>
<li>
<input type="radio" name="type" value="move_bio" id="hoverHandler"
onclick="toggleControl(this);" />
<label for="hoverHandler">Move (bioregion)</label>
</li>
<li>
<input type="radio" name="type" value="move_both" id="clickHandler"
onclick="toggleControl(this);" />
<label for="clickHandler">Move (both)</label>
</li>
</ul>
</div>
</div> </div>
<div id="themap" class="smallmap"></div>
<ul id="controlToggle">
<li>
<input type="radio" name="type" value="move_pop" id="moveHandler"
onclick="toggleControl(this);" checked="checked" />
<label for="moveHandler">Move (population)</label>
</li>
<li>
<input type="radio" name="type" value="move_bio" id="hoverHandler"
onclick="toggleControl(this);" />
<label for="hoverHandler">Move (bioregion)</label>
</li>
<li>
<input type="radio" name="type" value="move_both" id="clickHandler"
onclick="toggleControl(this);" />
<label for="clickHandler">Move (both)</label>
</li>
</ul>
<div id="attrsdiv"></div> <div id="attrsdiv"></div>
<div id="themap"> </div>
<script> <script>
/* /*
* Map * Map
*/ */
var map = new OpenLayers.Map('themap', { var map = new OpenLayers.Map({
projection: new OpenLayers.Projection("EPSG:900913"), div: "themap",
units: "m", projection: "EPSG:900913",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
controls: [] controls: []
}); });
var world_utfgrid = new OpenLayers.Layer.UTFGrid( var world_utfgrid = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer', "World Population",
//"http://tiles/world_utfgrid/${z}/${x}/${y}.json"
"./utfgrid/world_utfgrid/${z}/${x}/${y}.json" "./utfgrid/world_utfgrid/${z}/${x}/${y}.json"
); );
var bio_utfgrid = new OpenLayers.Layer.UTFGrid( var bio_utfgrid = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer of World Bioregions', "World Bioregions",
//"http://tiles/bailey_utfgrid/${z}/${x}/${y}.json"
"./utfgrid/bio_utfgrid/${z}/${x}/${y}.json" "./utfgrid/bio_utfgrid/${z}/${x}/${y}.json"
); );
map.addLayers([bio_utfgrid,world_utfgrid]); map.addLayers([bio_utfgrid,world_utfgrid]);
controls = { var callback = function(dataLookup) {
'move_pop': new OpenLayers.Control.UTFGrid({ var msg = "";
'div': 'attrsdiv', if (dataLookup) {
'layers': [world_utfgrid], var layer, data;
'handlerMode': 'move' for (var idx in dataLookup) {
layer = map.layers[idx];
data = dataLookup[idx];
if (data) {
msg += "<strong>" + layer.name + "</strong><br>";
for (var key in data) {
msg += key + ": " + data[key] + "<br>";
}
}
}
}
document.getElementById("attrsdiv").innerHTML = msg;
};
var controls = {
move_pop: new OpenLayers.Control.UTFGrid({
callback: callback,
layers: [world_utfgrid],
handlerMode: 'move'
}), }),
'move_bio': new OpenLayers.Control.UTFGrid({ move_bio: new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv', callback: callback,
'layers': [bio_utfgrid], layers: [bio_utfgrid],
'handlerMode': 'move' handlerMode: 'move'
}), }),
'move_both': new OpenLayers.Control.UTFGrid({ move_both: new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv', callback: callback,
'layers': null, // same as [bio_utfgrid,world_utfgrid] layers: null, // same as [bio_utfgrid,world_utfgrid]
'handlerMode': 'move' handlerMode: 'move'
}) })
} };
var control; var control;
for(var key in controls) { for(var key in controls) {
control = controls[key]; control = controls[key];
@@ -98,11 +108,8 @@
} }
// Visible Layers // Visible Layers
var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", var osm = new OpenLayers.Layer.OSM();
"http://vmap0.tiles.osgeo.org/wms/vmap0", map.addLayer(osm);
{layers: 'basic'}
);
map.addLayer(ol_wms);
map.zoomTo(1); map.zoomTo(1);
</script> </script>
</body> </body>
+3
View File
@@ -124,6 +124,7 @@
"OpenLayers/Tile.js", "OpenLayers/Tile.js",
"OpenLayers/Tile/Image.js", "OpenLayers/Tile/Image.js",
"OpenLayers/Tile/Image/IFrame.js", "OpenLayers/Tile/Image/IFrame.js",
"OpenLayers/Tile/UTFGrid.js",
"OpenLayers/Layer/Image.js", "OpenLayers/Layer/Image.js",
"OpenLayers/Layer/SphericalMercator.js", "OpenLayers/Layer/SphericalMercator.js",
"OpenLayers/Layer/EventPane.js", "OpenLayers/Layer/EventPane.js",
@@ -146,6 +147,7 @@
"OpenLayers/Layer/GeoRSS.js", "OpenLayers/Layer/GeoRSS.js",
"OpenLayers/Layer/Boxes.js", "OpenLayers/Layer/Boxes.js",
"OpenLayers/Layer/XYZ.js", "OpenLayers/Layer/XYZ.js",
"OpenLayers/Layer/UTFGrid.js",
"OpenLayers/Layer/OSM.js", "OpenLayers/Layer/OSM.js",
"OpenLayers/Layer/Bing.js", "OpenLayers/Layer/Bing.js",
"OpenLayers/Layer/TMS.js", "OpenLayers/Layer/TMS.js",
@@ -203,6 +205,7 @@
"OpenLayers/Control/WMTSGetFeatureInfo.js", "OpenLayers/Control/WMTSGetFeatureInfo.js",
"OpenLayers/Control/Graticule.js", "OpenLayers/Control/Graticule.js",
"OpenLayers/Control/TransformFeature.js", "OpenLayers/Control/TransformFeature.js",
"OpenLayers/Control/UTFGrid.js",
"OpenLayers/Control/SLDSelect.js", "OpenLayers/Control/SLDSelect.js",
"OpenLayers/Geometry.js", "OpenLayers/Geometry.js",
"OpenLayers/Geometry/Collection.js", "OpenLayers/Geometry/Collection.js",
+20 -103
View File
@@ -31,9 +31,12 @@
* map.addLayer(world_utfgrid); * map.addLayer(world_utfgrid);
* *
* var control = new OpenLayers.Control.UTFGrid({ * var control = new OpenLayers.Control.UTFGrid({
* 'div': 'attrsdiv', * layers: [world_utfgrid],
* 'layers': [world_utfgrid], * handlerMode: 'move',
* 'handlerMode': 'move' * callback: function(dataLookup) {
* // do something with returned data
*
* }
* }) * })
* (end code) * (end code)
* *
@@ -58,18 +61,6 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
*/ */
layers: null, layers: null,
/**
* Property: element
* {DOMElement}
*/
element: null,
/**
* Property: debugElement
* {DOMElement}
*/
debugElement: null,
/* Property: defaultHandlerOptions /* Property: defaultHandlerOptions
* The default opts passed to the handler constructors * The default opts passed to the handler constructors
*/ */
@@ -153,9 +144,6 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
options = options || {}; options = options || {};
options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions;
OpenLayers.Control.prototype.initialize.apply(this, [options]); OpenLayers.Control.prototype.initialize.apply(this, [options]);
if (options.div) {
this.element = OpenLayers.Util.getElement(options.div);
}
this.resetHandler(); this.resetHandler();
}, },
@@ -186,110 +174,39 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
} }
var layers = this.findLayers(); var layers = this.findLayers();
var globalAttrs = {};
if (layers.length > 0) { if (layers.length > 0) {
var layer; var dataLookup = {};
var layer, idx;
for (var i=0, len=layers.length; i<len; i++) { for (var i=0, len=layers.length; i<len; i++) {
layer = layers[i]; layer = layers[i];
var info = layer.getTileInfo( lonLat ); idx = this.map.layers.indexOf(layer);
this.writeDebugInfo(info); dataLookup[idx] = layer.getData(lonLat);
var tile = info.tile;
var localAttrs = null;
var resolution = layer.utfgridResolution || 4;
if (tile !== null && typeof(tile) !== 'undefined') {
var data = tile.json
if (data !== null) {
var code = this.resolveCode(data.grid[
Math.floor((info.j) / resolution)
].charCodeAt(
Math.floor((info.i) / resolution)
));
localAttrs = data.data[data.keys[code]];
for (var property in localAttrs) {
// If attribute names collide, last one takes it
globalAttrs[property] = localAttrs[property];
}
}
}
} }
this.callback(globalAttrs); // perhaps pass tile, lonLat? this.callback(dataLookup); // perhaps pass tile, lonLat?
} }
}, },
/** Method: writeDebugInfo
* Writes out debug info on event
* Only fired off if this.debugElement is set
*
*/
writeDebugInfo: function(info) {
var debug = "<ul>";
debug += "<li>i :" + info.i + "</li>";
debug += "<li>j :" + info.j + "</li>";
debug += "<li>globalrow :" + info.globalRow + "</li>";
debug += "<li>globalcol :" + info.globalCol + "</li>";
debug += "<li>gridrow :" + info.gridRow + "</li>";
debug += "<li>gridcol :" + info.gridCol + "</li>";
debug += "</ul>";
if (this.debugElement) {
this.debugElement.innerHTML = debug;
}
},
/** /**
* APIMethod: callback * APIMethod: callback
* Takes the attrs and does somethings with them * Function to be called when a mouse event corresponds with a location that
* The default behavior is to make a simple table * includes data in one of the configured UTFGrid layers.
* and write to a div (defined by this.element)
* *
* Parameters: * Parameters:
* attrs - {Object} * dataLookup - {Object} Keys of this object are layer indexes and can be
* * used to resolve a layer in the map.layers array. The structure of
* Returns: * the property values depend on the data included in the underlying
* {Boolean} - was the element updated? * UTFGrid and may be any valid JSON type.
*/ */
callback: function(attrs) { callback: function(dataLookup) {
if (attrs !== null && typeof(attrs) !== 'undefined') { // to be provided in the constructor
val = "<table>";
for(var index in attrs) {
val += "<tr><th>" + index + "</th><td>" + attrs[index] + "</td></tr>";
}
val += "</table>";
this.element.innerHTML = val;
return true;
} else {
this.element.innerHTML = '';
return false;
}
},
/**
* Method: resolveCode
* Resolve the UTF-8 encoding stored in grids to simple
* number values.
* See the [utfgrid section of the mbtiles spec](https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md)
* for details.
*
* Parameters:
* key - {Integer}
*
* Returns:
* {Integer} Adjusted key for non-escaped chars
*/
resolveCode: function(key) {
if (key >= 93) key--;
if (key >= 35) key--;
key -= 32;
return key;
}, },
/** /**
* Method: reset * Method: reset
* Resets the element * Calls the callback with null.
*/ */
reset: function(evt) { reset: function(evt) {
this.callback(null); this.callback(null);
if (this.element)
this.element.innerHTML = '';
}, },
/** /**
+48 -1
View File
@@ -180,7 +180,7 @@ OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.Grid, {
utfgridResolution: 4, utfgridResolution: 4,
/** /**
* APIMethod: getTileInfo * Method: getTileInfo
* Get tile information for a given location at the current map resolution. * Get tile information for a given location at the current map resolution.
* *
* Parameters: * Parameters:
@@ -246,6 +246,53 @@ OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.Grid, {
j: Math.floor((fy - globalRow) * this.tileSize.h) j: Math.floor((fy - globalRow) * this.tileSize.h)
}; };
}, },
/**
* APIProperty: getData
* Get tile data associated with a map location.
*
* Parameters:
* location - {<OpenLayers.LonLat>} map location
*
* Returns:
* {Object} The UTFGrid data corresponding to the given map location.
*/
getData: function(location) {
var info = this.getTileInfo(location);
var tile = info.tile;
var data;
if (tile) {
var resolution = this.utfgridResolution;
var json = tile.json
if (json) {
var code = this.resolveCode(json.grid[
Math.floor((info.j) / resolution)
].charCodeAt(
Math.floor((info.i) / resolution)
));
data = json.data[json.keys[code]];
}
}
return data;
},
/**
* Method: resolveCode
* Resolve the UTF-8 encoding stored in grids to simple number values.
* See the UTFGrid spec for details.
*
* Parameters:
* key - {Integer}
*
* Returns:
* {Integer} Adjusted key for non-escaped chars
*/
resolveCode: function(key) {
if (key >= 93) key--;
if (key >= 35) key--;
key -= 32;
return key;
},
/** /**
* APIProperty: tileClass * APIProperty: tileClass