diff --git a/examples/kml.html b/examples/kml.html
index 4c243a0950..ee44518836 100644
--- a/examples/kml.html
+++ b/examples/kml.html
@@ -43,6 +43,11 @@
KML
+
diff --git a/examples/kml.js b/examples/kml.js
index dbbeb5da6e..2282e1504d 100644
--- a/examples/kml.js
+++ b/examples/kml.js
@@ -43,6 +43,20 @@ var map = new ol.Map({
var kml = new ol.parser.KML({
maxDepth: 1, dimension: 2, extractStyles: true, extractAttributes: true});
+map.on('mousemove', function(evt) {
+ map.getFeatureInfo({
+ pixel: evt.getPixel(),
+ layers: [vector],
+ success: function(features) {
+ var info = [];
+ for (var i = 0, ii = features.length; i < ii; ++i) {
+ info.push(features[i].get('name'));
+ }
+ document.getElementById('info').innerHTML = info.join(', ') || ' ';
+ }
+ });
+});
+
var url = 'data/kml/lines.kml';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
diff --git a/src/ol/extent.js b/src/ol/extent.js
index d37dc87794..1f54e4bf65 100644
--- a/src/ol/extent.js
+++ b/src/ol/extent.js
@@ -57,16 +57,26 @@ ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {
/**
- * Checks if the passed coordinate is contained or on the edge
+ * Checks if (one of) the passed coordinate(s) is contained or on the edge
* of the extent.
*
* @param {ol.Extent} extent Extent.
- * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Coordinate|Array.} coordinates Coordinate(s).
* @return {boolean} Contains.
*/
-ol.extent.containsCoordinate = function(extent, coordinate) {
- return extent[0] <= coordinate[0] && coordinate[0] <= extent[1] &&
- extent[2] <= coordinate[1] && coordinate[1] <= extent[3];
+ol.extent.containsCoordinate = function(extent, coordinates) {
+ coordinates = goog.isArray(coordinates[0]) ? coordinates : [coordinates];
+ var contains = false,
+ coordinate, i;
+ for (i = coordinates.length - 1; i >= 0; --i) {
+ coordinate = coordinates[i];
+ if (extent[0] <= coordinate[0] && coordinate[0] <= extent[1] &&
+ extent[2] <= coordinate[1] && coordinate[1] <= extent[3]) {
+ contains = true;
+ break;
+ }
+ }
+ return contains;
};
diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
index c941a10898..1b1239435f 100644
--- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
+++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
@@ -137,6 +137,18 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
*/
this.tileGrid_ = null;
+ /**
+ * @type {Object.>}
+ * @private
+ */
+ this.symbolSizes_ = {};
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this.maxSymbolSize_ = [0, 0];
+
/**
* @private
* @type {function()}
@@ -161,6 +173,8 @@ ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(opt_extent) {
// TODO: implement this
}
this.tileCache_.clear();
+ this.symbolSizes_ = {};
+ this.maxSymbolSize_ = [0, 0];
};
@@ -198,40 +212,50 @@ ol.renderer.canvas.VectorLayer.prototype.getTransform = function() {
*/
ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
function(pixel, success) {
- // TODO adjust pixel tolerance for applied styles
- var minPixel = new ol.Pixel(pixel.x - 1, pixel.y - 1);
- var maxPixel = new ol.Pixel(pixel.x + 1, pixel.y + 1);
var map = this.getMap();
- var locationMin = map.getCoordinateFromPixel(minPixel);
- var locationMax = map.getCoordinateFromPixel(maxPixel);
+ var hw = this.maxSymbolSize_[0] / 2;
+ var hh = this.maxSymbolSize_[1] / 2;
+ var location = map.getCoordinateFromPixel(pixel);
+ var locationMin = [location[0] - hw, location[1] - hh];
+ var locationMax = [location[0] + hw, location[1] + hh];
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
var filter = new ol.filter.Extent(locationBbox);
- // TODO do a real intersect against the filtered result for exact matches
var candidates = this.getLayer().getFeatures(filter);
- var location = map.getCoordinateFromPixel(pixel);
- // TODO adjust tolerance for stroke width or use configurable tolerance
- var tolerance = map.getView().getView2D().getResolution() * 3;
var result = [];
- var candidate, geom;
+ var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
+ coordinates, j;
for (var i = 0, ii = candidates.length; i < ii; ++i) {
candidate = candidates[i];
geom = candidate.getGeometry();
- if (goog.isFunction(geom.containsCoordinate)) {
+ type = geom.getType();
+ if (type === ol.geom.GeometryType.POINT ||
+ type === ol.geom.GeometryType.MULTIPOINT) {
+ // For points, check if the pixel coordinate is inside the candidate's
+ // symbol
+ symbolSize = this.symbolSizes_[goog.getUid(candidate)];
+ halfWidth = symbolSize[0] / 2;
+ halfHeight = symbolSize[1] / 2;
+ symbolBounds = ol.extent.boundingExtent(
+ [[location[0] - halfWidth, location[1] - halfHeight],
+ [location[0] + halfWidth, location[1] + halfHeight]]);
+ coordinates = geom.getCoordinates();
+ if (ol.extent.containsCoordinate(symbolBounds, coordinates)) {
+ result.push(candidate);
+ }
+ } else if (goog.isFunction(geom.containsCoordinate)) {
// For polygons, check if the pixel location is inside the polygon
if (geom.containsCoordinate(location)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
- // For lines, check if the ditance to the pixel location is within the
- // tolerance threshold
- if (geom.distanceFromCoordinate(location) < tolerance) {
+ // For lines, check if the distance to the pixel location is
+ // within the rendered line width
+ if (2 * geom.distanceFromCoordinate(location) <=
+ this.symbolSizes_[goog.getUid(candidate)][0]) {
result.push(candidate);
}
- } else {
- // For points, the bbox filter is all we need
- result.push(candidate);
}
}
goog.global.setTimeout(function() { success(result); }, 0);
@@ -397,6 +421,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
}
}
+ var renderedNew = false;
renderByGeometryType:
for (type in featuresToRender) {
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender[type]);
@@ -409,9 +434,16 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
if (deferred) {
break renderByGeometryType;
}
+ renderedNew = true;
}
}
+ if (renderedNew) {
+ goog.object.extend(this.symbolSizes_,
+ sketchCanvasRenderer.getSymbolSizes());
+ this.maxSymbolSize_ = sketchCanvasRenderer.getMaxSymbolSize();
+ }
+
if (!deferred) {
goog.object.extend(tilesToRender, tilesOnSketchCanvas);
}
diff --git a/src/ol/renderer/canvas/canvasvectorrenderer.js b/src/ol/renderer/canvas/canvasvectorrenderer.js
index 4e4696d221..9d0222ca50 100644
--- a/src/ol/renderer/canvas/canvasvectorrenderer.js
+++ b/src/ol/renderer/canvas/canvasvectorrenderer.js
@@ -79,6 +79,34 @@ ol.renderer.canvas.VectorRenderer =
*/
this.iconLoadedCallback_ = opt_iconLoadedCallback;
+ /**
+ * @type {Object.>}
+ * @private
+ */
+ this.symbolSizes_ = {};
+
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this.maxSymbolSize_ = [0, 0];
+
+};
+
+
+/**
+ * @return {Object.>} Symbolizer sizes.
+ */
+ol.renderer.canvas.VectorRenderer.prototype.getSymbolSizes = function() {
+ return this.symbolSizes_;
+};
+
+
+/**
+ * @return {Array.} Maximum symbolizer size.
+ */
+ol.renderer.canvas.VectorRenderer.prototype.getMaxSymbolSize = function() {
+ return this.maxSymbolSize_;
};
@@ -129,7 +157,8 @@ ol.renderer.canvas.VectorRenderer.prototype.renderLineStringFeatures_ =
function(features, symbolizer) {
var context = this.context_,
- i, ii, geometry, components, j, jj, line, dim, k, kk, x, y;
+ i, ii, feature, id, currentSize, geometry, components, j, jj, line, dim,
+ k, kk, x, y;
context.globalAlpha = symbolizer.opacity;
context.strokeStyle = symbolizer.strokeColor;
@@ -138,7 +167,15 @@ ol.renderer.canvas.VectorRenderer.prototype.renderLineStringFeatures_ =
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
context.beginPath();
for (i = 0, ii = features.length; i < ii; ++i) {
- geometry = features[i].getGeometry();
+ feature = features[i];
+ id = goog.getUid(feature);
+ currentSize = goog.isDef(this.symbolSizes_[id]) ?
+ this.symbolSizes_[id] : [0];
+ currentSize[0] = Math.max(currentSize[0], context.lineWidth);
+ this.symbolSizes_[id] = currentSize;
+ this.maxSymbolSize_ = [Math.max(currentSize[0], this.maxSymbolSize_[0]),
+ Math.max(currentSize[0], this.maxSymbolSize_[1])];
+ geometry = feature.getGeometry();
if (geometry instanceof ol.geom.LineString) {
components = [geometry];
} else {
@@ -175,7 +212,8 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPointFeatures_ =
function(features, symbolizer) {
var context = this.context_,
- content, alpha, i, ii, geometry, components, j, jj, point, vec;
+ content, alpha, i, ii, feature, id, size, geometry, components, j, jj,
+ point, vec;
if (symbolizer instanceof ol.style.ShapeLiteral) {
content = ol.renderer.canvas.VectorRenderer.renderShape(symbolizer);
@@ -198,7 +236,18 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPointFeatures_ =
context.setTransform(1, 0, 0, 1, -midWidth, -midHeight);
context.globalAlpha = alpha;
for (i = 0, ii = features.length; i < ii; ++i) {
- geometry = features[i].getGeometry();
+ feature = features[i];
+ id = goog.getUid(feature);
+ size = this.symbolSizes_[id];
+ this.symbolSizes_[id] = goog.isDef(size) ?
+ [Math.max(size[0], content.width * this.inverseScale_),
+ Math.max(size[1], content.height * this.inverseScale_)] :
+ [content.width * this.inverseScale_,
+ content.height * this.inverseScale_];
+ this.maxSymbolSize_ =
+ [Math.max(this.maxSymbolSize_[0], this.symbolSizes_[id][0]),
+ Math.max(this.maxSymbolSize_[1], this.symbolSizes_[id][1])];
+ geometry = feature.getGeometry();
if (geometry instanceof ol.geom.Point) {
components = [geometry];
} else {