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 {