From af768528413987592b3be78679d2849ea4881cfa Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 2 Jan 2008 19:16:58 +0000 Subject: [PATCH] Giving vector features an onScreen method. By default, this uses geometry.intersects. If a rougher approximation will do, call with boundsOnly set to true. r=crschmidt (closes #1238) git-svn-id: http://svn.openlayers.org/trunk/openlayers@5625 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- lib/OpenLayers/BaseTypes/Bounds.js | 19 ++++++++++++++++ lib/OpenLayers/Feature/Vector.js | 29 +++++++++++++++++++++---- tests/BaseTypes/test_Bounds.html | 25 +++++++++++++++++++++ tests/Feature/test_Vector.html | 35 ++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/lib/OpenLayers/BaseTypes/Bounds.js b/lib/OpenLayers/BaseTypes/Bounds.js index 0504abc775..8adb0d99b0 100644 --- a/lib/OpenLayers/BaseTypes/Bounds.js +++ b/lib/OpenLayers/BaseTypes/Bounds.js @@ -148,6 +148,25 @@ OpenLayers.Bounds = OpenLayers.Class({ return bbox; }, + /** + * APIMethod: toGeometry + * Create a new polygon geometry based on this bounds. + * + * Returns: + * {} A new polygon with the coordinates + * of this bounds. + */ + toGeometry: function() { + return new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing([ + new OpenLayers.Geometry.Point(this.left, this.bottom), + new OpenLayers.Geometry.Point(this.right, this.bottom), + new OpenLayers.Geometry.Point(this.right, this.top), + new OpenLayers.Geometry.Point(this.left, this.top) + ]) + ]); + }, + /** * APIMethod: getWidth * diff --git a/lib/OpenLayers/Feature/Vector.js b/lib/OpenLayers/Feature/Vector.js index 2811a7aa3e..bc0f26cee0 100644 --- a/lib/OpenLayers/Feature/Vector.js +++ b/lib/OpenLayers/Feature/Vector.js @@ -114,13 +114,34 @@ OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { /** * Method: onScreen - * HACK - we need to rewrite this for non-point geometry + * Determine whether the feature is within the map viewport. This method + * tests for an intersection between the geometry and the viewport + * bounds. If a more effecient but less precise geometry bounds + * intersection is desired, call the method with the boundsOnly + * parameter true. + * + * Parameters: + * boundsOnly - {Boolean} Only test whether a feature's bounds intersects + * the viewport bounds. Default is false. If false, the feature's + * geometry must intersect the viewport for onScreen to return true. * * Returns: - * {Boolean} For now just returns null + * {Boolean} The feature is currently visible on screen (optionally + * based on its bounds if boundsOnly is true). */ - onScreen:function() { - return null; + onScreen:function(boundsOnly) { + var onScreen = false; + if(this.layer && this.layer.map) { + var screenBounds = this.layer.map.getExtent(); + if(boundsOnly) { + var featureBounds = this.geometry.getBounds(); + onScreen = screenBounds.intersectsBounds(featureBounds); + } else { + var screenPoly = screenBounds.toGeometry(); + onScreen = screenPoly.intersects(this.geometry); + } + } + return onScreen; }, /** diff --git a/tests/BaseTypes/test_Bounds.html b/tests/BaseTypes/test_Bounds.html index 6f8b0ce8b2..b2dc43d7ce 100644 --- a/tests/BaseTypes/test_Bounds.html +++ b/tests/BaseTypes/test_Bounds.html @@ -76,6 +76,31 @@ t.eq( bounds.toArray(), [1,2,3,4], "toArray() returns correct value." ); } + function test_Bounds_toGeometry(t) { + t.plan(7); + var minx = Math.random(); + var miny = Math.random(); + var maxx = Math.random(); + var maxy = Math.random(); + var bounds = new OpenLayers.Bounds(minx, miny, maxx, maxy); + var poly = bounds.toGeometry(); + t.eq(poly.CLASS_NAME, "OpenLayers.Geometry.Polygon", + "polygon instance created"); + t.eq(poly.components.length, 1, + "polygon with one ring created"); + var ring = poly.components[0]; + t.eq(ring.components.length, 5, + "four sided polygon created"); + t.eq(ring.components[0].x, minx, + "bounds left preserved"); + t.eq(ring.components[0].y, miny, + "bounds bottom preserved"); + t.eq(ring.components[2].x, maxx, + "bounds left preserved"); + t.eq(ring.components[2].y, maxy, + "bounds bottom preserved"); + } + function test_04_Bounds_contains(t) { t.plan( 6 ); bounds = new OpenLayers.Bounds(10,10,40,40); diff --git a/tests/Feature/test_Vector.html b/tests/Feature/test_Vector.html index d65c6f9d07..1e7aadb9c1 100644 --- a/tests/Feature/test_Vector.html +++ b/tests/Feature/test_Vector.html @@ -23,6 +23,41 @@ "geometry.property set properly" ); } + function test_Feature_onScreen(t) { + t.plan(6); + var line = new OpenLayers.Geometry.LineString([ + new OpenLayers.Geometry.Point(0, 0), + new OpenLayers.Geometry.Point(10, 20) + ]); + var feature = new OpenLayers.Feature.Vector(line); + feature.layer = { + map: { + getExtent: function() { + return new OpenLayers.Bounds(5, 5, 10, 10); + } + } + }; + t.eq(feature.onScreen(), true, + "intersecting feature returns true for intersection"); + t.eq(feature.onScreen(true), true, + "intersecting feature returns true for bounds only"); + + // move the line so only the bounds intersects + line.move(0, 5); + t.eq(feature.onScreen(), false, + "bounds-only feature returns false for intersection"); + t.eq(feature.onScreen(true), true, + "bounds-only feature returns true for bounds only"); + + // move the line so bounds does not intersect + line.move(0, 10); + t.eq(feature.onScreen(), false, + "off-screen feature returns false for intersection"); + t.eq(feature.onScreen(true), false, + "off-screen feature returns false for bounds only"); + + } + function test_Feature_Vector_clone(t) { t.plan(5);