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

View File

@@ -1,23 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title> OpenLayers UTFGrid Demo </title>
<script src='./OpenLayers.js' type='text/javascript'></script>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<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>
#themap { width:512px; height:380px; border:1px black solid; }
#attrsdiv { width: 300px; height: 100px; float:right; border: 1px grey dashed;}
#attrsdiv {
float: right;
}
#controlToggle li { list-style: none; }
</style>
</head>
<body>
<h1> OpenLayers UTFGrid Demo </h1>
<h1 id="title">OpenLayers UTFGrid Demo</h1>
<div id="top">
<div>
<p>
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 id="shortdesc">
This page demonstrates the use of the OpenLayers UTFGrid Controls.
</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">
<li>
<input type="radio" name="type" value="move" id="moveHandler"
@@ -40,12 +48,8 @@
<label for="clickHandlerCustom">Click with custom callback</label>
</li>
</ul>
</div>
</div>
<div id="attrsdiv"></div>
<div id="themap">
</div>
<div>
<div id="docs">
<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
interactivity data for a tile in a space efficient manner. It is designed to be
@@ -63,48 +67,43 @@
/*
* Map
*/
var map = new OpenLayers.Map('themap', {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
var map = new OpenLayers.Map({
div: "themap",
projection: "EPSG:900913",
controls: [] // No default controls; no pan zoom for demo
});
/*
* Controls
*/
var callback = function(attributes) {
if (attributes) {
var msg = "<strong>In 2005, " + attributes.NAME
msg += " had a population of " + attributes.POP2005 + " people.</strong>";
var element = OpenLayers.Util.getElement('attrsdiv');
element.innerHTML = msg;
return true;
} else {
this.element.innerHTML = '';
return false;
var callback = function(dataLookup) {
var msg = "";
if (dataLookup) {
var data;
for (var idx in dataLookup) {
// idx can be used to retrieve layer from map.layers[idx]
data = dataLookup[idx];
msg += "<strong>In 2005, " + data.NAME + " had a population of " +
data.POP2005 + " people.</strong> ";
}
}
}
document.getElementById("attrsdiv").innerHTML = msg;
};
controls = {
'move': new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv',
'handlerMode': 'move'
var controls = {
move: new OpenLayers.Control.UTFGrid({
callback: callback,
handlerMode: 'move'
}),
'hover': new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv',
'handlerMode': 'hover'
hover: new OpenLayers.Control.UTFGrid({
callback: callback,
handlerMode: 'hover'
}),
'click': new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv',
'handlerMode': 'click'
}),
'click_callback': new OpenLayers.Control.UTFGrid({
'handlerMode': 'click',
'callback': callback
}),
}
click: new OpenLayers.Control.UTFGrid({
callback: callback,
handlerMode: 'click'
})
};
var control;
for(var key in controls) {
control = controls[key];
@@ -126,11 +125,8 @@
* Layers
*/
var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0",
{layers: 'basic'}
);
map.addLayer(ol_wms);
var osm = new OpenLayers.Layer.OSM();
map.addLayer(osm);
var grid_layer = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer',

View File

@@ -1,85 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<title> OpenLayers Multiple UTFGrid Demo </title>
<script src='./OpenLayers.js' type='text/javascript'></script>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<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>
#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; }
</style>
</head>
<body>
<h1> OpenLayers Multiple UTFGrid Demo </h1>
<h1 id="title">OpenLayers Multiple UTFGrid Demo</h1>
<div id="top">
<div>
<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 id="shortdesc">
This page demonstrates the use of the OpenLayers UTFGrid Controls with more than one UTFGrid Layer.
</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="themap"> </div>
<script>
/*
* Map
*/
var map = new OpenLayers.Map('themap', {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
var map = new OpenLayers.Map({
div: "themap",
projection: "EPSG:900913",
controls: []
});
var world_utfgrid = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer',
//"http://tiles/world_utfgrid/${z}/${x}/${y}.json"
"World Population",
"./utfgrid/world_utfgrid/${z}/${x}/${y}.json"
);
var bio_utfgrid = new OpenLayers.Layer.UTFGrid(
'Invisible UTFGrid Layer of World Bioregions',
//"http://tiles/bailey_utfgrid/${z}/${x}/${y}.json"
"World Bioregions",
"./utfgrid/bio_utfgrid/${z}/${x}/${y}.json"
);
map.addLayers([bio_utfgrid,world_utfgrid]);
controls = {
'move_pop': new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv',
'layers': [world_utfgrid],
'handlerMode': 'move'
var callback = function(dataLookup) {
var msg = "";
if (dataLookup) {
var layer, data;
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({
'div': 'attrsdiv',
'layers': [bio_utfgrid],
'handlerMode': 'move'
move_bio: new OpenLayers.Control.UTFGrid({
callback: callback,
layers: [bio_utfgrid],
handlerMode: 'move'
}),
'move_both': new OpenLayers.Control.UTFGrid({
'div': 'attrsdiv',
'layers': null, // same as [bio_utfgrid,world_utfgrid]
'handlerMode': 'move'
move_both: new OpenLayers.Control.UTFGrid({
callback: callback,
layers: null, // same as [bio_utfgrid,world_utfgrid]
handlerMode: 'move'
})
}
};
var control;
for(var key in controls) {
control = controls[key];
@@ -98,11 +108,8 @@
}
// Visible Layers
var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0",
{layers: 'basic'}
);
map.addLayer(ol_wms);
var osm = new OpenLayers.Layer.OSM();
map.addLayer(osm);
map.zoomTo(1);
</script>
</body>

View File

@@ -124,6 +124,7 @@
"OpenLayers/Tile.js",
"OpenLayers/Tile/Image.js",
"OpenLayers/Tile/Image/IFrame.js",
"OpenLayers/Tile/UTFGrid.js",
"OpenLayers/Layer/Image.js",
"OpenLayers/Layer/SphericalMercator.js",
"OpenLayers/Layer/EventPane.js",
@@ -146,6 +147,7 @@
"OpenLayers/Layer/GeoRSS.js",
"OpenLayers/Layer/Boxes.js",
"OpenLayers/Layer/XYZ.js",
"OpenLayers/Layer/UTFGrid.js",
"OpenLayers/Layer/OSM.js",
"OpenLayers/Layer/Bing.js",
"OpenLayers/Layer/TMS.js",
@@ -203,6 +205,7 @@
"OpenLayers/Control/WMTSGetFeatureInfo.js",
"OpenLayers/Control/Graticule.js",
"OpenLayers/Control/TransformFeature.js",
"OpenLayers/Control/UTFGrid.js",
"OpenLayers/Control/SLDSelect.js",
"OpenLayers/Geometry.js",
"OpenLayers/Geometry/Collection.js",

View File

@@ -31,9 +31,12 @@
* map.addLayer(world_utfgrid);
*
* var control = new OpenLayers.Control.UTFGrid({
* 'div': 'attrsdiv',
* 'layers': [world_utfgrid],
* 'handlerMode': 'move'
* layers: [world_utfgrid],
* handlerMode: 'move',
* callback: function(dataLookup) {
* // do something with returned data
*
* }
* })
* (end code)
*
@@ -58,18 +61,6 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
*/
layers: null,
/**
* Property: element
* {DOMElement}
*/
element: null,
/**
* Property: debugElement
* {DOMElement}
*/
debugElement: null,
/* Property: defaultHandlerOptions
* The default opts passed to the handler constructors
*/
@@ -153,9 +144,6 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
options = options || {};
options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions;
OpenLayers.Control.prototype.initialize.apply(this, [options]);
if (options.div) {
this.element = OpenLayers.Util.getElement(options.div);
}
this.resetHandler();
},
@@ -186,110 +174,39 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
}
var layers = this.findLayers();
var globalAttrs = {};
if (layers.length > 0) {
var layer;
var dataLookup = {};
var layer, idx;
for (var i=0, len=layers.length; i<len; i++) {
layer = layers[i];
var info = layer.getTileInfo( lonLat );
this.writeDebugInfo(info);
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];
}
}
}
idx = this.map.layers.indexOf(layer);
dataLookup[idx] = layer.getData(lonLat);
}
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
* Takes the attrs and does somethings with them
* The default behavior is to make a simple table
* and write to a div (defined by this.element)
* Function to be called when a mouse event corresponds with a location that
* includes data in one of the configured UTFGrid layers.
*
* Parameters:
* attrs - {Object}
*
* Returns:
* {Boolean} - was the element updated?
* 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
* the property values depend on the data included in the underlying
* UTFGrid and may be any valid JSON type.
*/
callback: function(attrs) {
if (attrs !== null && typeof(attrs) !== 'undefined') {
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;
callback: function(dataLookup) {
// to be provided in the constructor
},
/**
* Method: reset
* Resets the element
* Calls the callback with null.
*/
reset: function(evt) {
this.callback(null);
if (this.element)
this.element.innerHTML = '';
},
/**

View File

@@ -180,7 +180,7 @@ OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.Grid, {
utfgridResolution: 4,
/**
* APIMethod: getTileInfo
* Method: getTileInfo
* Get tile information for a given location at the current map resolution.
*
* Parameters:
@@ -246,6 +246,53 @@ OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.Grid, {
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