Providing a method to get data from the layer.
I think it should be the job of the layer to retrieve data for a given location (instead of the control). The first part of this change creates a `getData` method on the layer and updates the control to use this method. The second part of this change removes the assumption that the data returned will be an simple object representing feature attributes. The UTFGrid specification doesn't say anything about the structure of property values in the optional data member. The examples given in the spec use string values. The default callback previously assumed that the data could be rendered in a two column table. I think it would make more sense not to make this assumption. With this change, the user must always provide a callback to do anything with returned data.
This commit is contained in:
@@ -8,7 +8,9 @@
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<style>
|
||||
#attrsdiv { width: 300px; height: 100px; float:right; border: 1px grey dashed;}
|
||||
#attrsdiv {
|
||||
float: right;
|
||||
}
|
||||
#controlToggle li { list-style: none; }
|
||||
</style>
|
||||
</head>
|
||||
@@ -22,7 +24,7 @@
|
||||
<div id="attrsdiv"></div>
|
||||
<div id="themap" class="smallmap"></div>
|
||||
<p>
|
||||
When the selected event is triggered, the underlying feature attributes are shown on the right.
|
||||
When the selected event is triggered, the underlying feature attributes are shown below.
|
||||
</p>
|
||||
<ul id="controlToggle">
|
||||
<li>
|
||||
@@ -74,36 +76,33 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
var controls = {
|
||||
move: new OpenLayers.Control.UTFGrid({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
handlerMode: 'move'
|
||||
}),
|
||||
hover: new OpenLayers.Control.UTFGrid({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
handlerMode: 'hover'
|
||||
}),
|
||||
click: new OpenLayers.Control.UTFGrid({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
handlerMode: 'click'
|
||||
}),
|
||||
click_callback: new OpenLayers.Control.UTFGrid({
|
||||
handlerMode: 'click',
|
||||
callback: callback
|
||||
}),
|
||||
})
|
||||
};
|
||||
var control;
|
||||
for(var key in controls) {
|
||||
|
||||
@@ -8,37 +8,34 @@
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<style>
|
||||
#attrsdiv { width: 300px; height: 100px; float:right; border: 1px grey dashed;}
|
||||
#controlToggle li { list-style: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="title">OpenLayers Multiple UTFGrid Demo</h1>
|
||||
|
||||
<div>
|
||||
<div id="shortdesc">
|
||||
This page demonstrates the use of the OpenLayers UTFGrid Controls with more than one UTFGrid Layer.
|
||||
</div>
|
||||
<div id="attrsdiv"></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="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>
|
||||
<script>
|
||||
/*
|
||||
* Map
|
||||
@@ -50,28 +47,45 @@
|
||||
});
|
||||
|
||||
var world_utfgrid = new OpenLayers.Layer.UTFGrid(
|
||||
'Invisible UTFGrid Layer',
|
||||
"World Population",
|
||||
"./utfgrid/world_utfgrid/${z}/${x}/${y}.json"
|
||||
);
|
||||
var bio_utfgrid = new OpenLayers.Layer.UTFGrid(
|
||||
'Invisible UTFGrid Layer of World Bioregions',
|
||||
"World Bioregions",
|
||||
"./utfgrid/bio_utfgrid/${z}/${x}/${y}.json"
|
||||
);
|
||||
map.addLayers([bio_utfgrid,world_utfgrid]);
|
||||
|
||||
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({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
layers: [world_utfgrid],
|
||||
handlerMode: 'move'
|
||||
}),
|
||||
move_bio: new OpenLayers.Control.UTFGrid({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
layers: [bio_utfgrid],
|
||||
handlerMode: 'move'
|
||||
}),
|
||||
move_both: new OpenLayers.Control.UTFGrid({
|
||||
div: 'attrsdiv',
|
||||
callback: callback,
|
||||
layers: null, // same as [bio_utfgrid,world_utfgrid]
|
||||
handlerMode: 'move'
|
||||
})
|
||||
|
||||
@@ -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,12 +61,6 @@ OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, {
|
||||
*/
|
||||
layers: null,
|
||||
|
||||
/**
|
||||
* Property: element
|
||||
* {DOMElement}
|
||||
*/
|
||||
element: null,
|
||||
|
||||
/* Property: defaultHandlerOptions
|
||||
* The default opts passed to the handler constructors
|
||||
*/
|
||||
@@ -147,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();
|
||||
},
|
||||
|
||||
@@ -180,90 +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 );
|
||||
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?
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 = '';
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user