New vector rendering for better performance and less renderer specific limitations. r=elemoine (closes #1675, closes #1656, closes #1631, closes #1431, closes #1709)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@7930 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2008-09-02 17:17:52 +00:00
parent ede7bef13c
commit c12cb25aee
12 changed files with 676 additions and 155 deletions

View File

@@ -126,23 +126,28 @@
}
function test_Layer_Vector_drawFeature(t) {
t.plan(4);
var layer = new OpenLayers.Layer.Vector("Test Layer");
var map = new OpenLayers.Map('map');
t.plan(6);
var layer = new OpenLayers.Layer.Vector("Test Layer", {isBaseLayer: true});
var map = new OpenLayers.Map('map', {
maxExtent: new OpenLayers.Bounds(-100, -100, 100, 100)
});
map.addLayer(layer);
var geometry = new OpenLayers.Geometry.Point(10, 10);
var feature = new OpenLayers.Feature.Vector(geometry);
var f, s;
// Layer renderer needs a destroy, and draw, for functional tests.
// Bogus layer renderer needs some methods
// for functional tests.
layer.renderer = {
drawFeature: function(feature, style) {
f = feature;
s = style;
},
root: document.createElement("div"),
destroy: function() { },
eraseFeatures: function() {}
eraseFeatures: function() {},
setExtent: function() {}
};
@@ -168,6 +173,17 @@
t.eq(customStyle.foo, s.foo,
"given a custom style, renders with that");
// the real renderer's drawFeature method is tested in Renderer.html
layer.renderer.drawFeature = function(feature) {
return(feature.geometry.getBounds().intersectsBounds(map.getExtent()));
}
layer.addFeatures([feature]);
map.setCenter(new OpenLayers.Bounds(0, 0, 0, 0), 6);
t.ok(layer.unrenderedFeatures[feature.id], "Did not render feature outside the viewport.");
map.panTo(new OpenLayers.LonLat(10, 10));
t.ok(!layer.unrenderedFeatures[feature.id], "Rendered feature inside the viewport.");
layer.features = [];
}
function test_Layer_Vector_eraseFeatures(t) {

View File

@@ -26,7 +26,7 @@
var r = new OpenLayers.Renderer();
var extent = new OpenLayers.Bounds(1,2,3,4);
r.resolution = 1;
r.setExtent(extent);
r.setExtent(extent, true);
t.ok(r.extent.equals(extent), "extent is correctly set");
t.eq(r.resolution, null, "resolution nullified");
}

View File

@@ -134,7 +134,6 @@
var r = create_renderer();
var element = document.createElement("div");
document.body.appendChild(element);
r.root = element;
r.nodeFactory = function(id, type) {
@@ -142,14 +141,15 @@
return element;
};
var g_Node = null;
var b_Node = null;
r.drawGeometryNode = function(node, geometry, style) {
g_Node = node;
return node;
return {node: node, complete: true};
};
r.redrawBackgroundNode = function(id, geometry, style, featureId) {
var el = r.nodeFactory();
el.id = "foo_background";
r.root.appendChild(el);
b_Node = r.nodeFactory();
b_Node.id = "foo_background";
r.root.appendChild(b_Node);
};
r.getNodeType = function(geometry, style) {
@@ -163,20 +163,25 @@
var featureId = 'dude';
r.drawGeometry(geometry, style, featureId);
t.ok(g_Node.parentNode == r.root, "node is correctly appended to root");
t.eq(r.root.childNodes.length, 2, "redrawBackgroundNode appended background node");
t.ok(b_Node.parentNode == r.root, "redrawBackgroundNode appended background node");
t.eq(g_Node._featureId, 'dude', "_featureId is correct");
t.eq(g_Node._style.backgroundGraphic, "foo", "_style is correct");
t.eq(g_Node._geometryClass, 'bar', "_geometryClass is correct");
var _getElement = OpenLayers.Util.getElement;
OpenLayers.Util.getElement = function(id) {
return g_Node;
var returnNode = function(id) {
return id == "foo_background" ? b_Node : g_Node;
}
var _getElement = document.getElementById;
document.getElementById = returnNode;
OpenLayers.Util.getElement = returnNode;
style = {'display':'none'};
r.drawGeometry(geometry, style, featureId);
t.ok(g_Node.parentNode != r.root, "node is correctly removed");
t.ok(!document.getElementById("foo_background"), "background node correctly removed")
t.ok(b_Node.parentNode != r.root, "background node correctly removed")
document.getElementById = _getElement;
tearDown();
}
@@ -216,7 +221,7 @@
properDraw = true;
return {};
};
geometry = {CLASS_NAME: 'OpenLayers.Geometry.LineString'};
geometry = {id: "foo", CLASS_NAME: 'OpenLayers.Geometry.LineString'};
style = true;
r.drawGeometry(geometry, style);
t.ok(properDraw, "drawGeometry called drawLineString when passed a line string");

View File

@@ -79,7 +79,7 @@
// test extent changes
var extent = new OpenLayers.Bounds(4,3,2,1);
r.setExtent(extent);
t.eq(r.rendererRoot.getAttributeNS(null, "viewBox"), "6 6 4 4", "rendererRoot viewBox is correct after a new setExtent");
t.eq(r.root.getAttributeNS(null, "transform").replace(/ /g, ""), "translate(-6,-6)", "rendererRoot viewBox is correct after a new setExtent");
OpenLayers.Renderer.Elements.prototype.setExtent =
OpenLayers.Renderer.Elements.prototype._setExtent;
@@ -128,7 +128,7 @@
return;
}
t.plan(6);
t.plan(5);
var r = new OpenLayers.Renderer.SVG(document.body);
r.resolution = 0.5;
@@ -151,14 +151,22 @@
// #1274: out of bound node fails when first added
var geometry = {
x: 10000000,
y: 200000000
y: 200000000,
CLASS_NAME: "OpenLayers.Geometry.Point",
id: "foo"
}
node.id = geometry.id;
r.root.appendChild(node);
var drawCircleCalled = false;
r.drawCircle = function() {
drawCircleCalled = true;
return OpenLayers.Renderer.SVG.prototype.drawCircle.apply(r, arguments);
}
r.drawCircle(node, geometry, "blah_4000");
t.eq(node.getAttributeNS(null, 'cx'), '', "cx is correct");
t.eq(node.getAttributeNS(null, 'cy'), '', "cy is correct");
t.eq(node.getAttributeNS(null, 'r'), '0', "r is correct");
r.drawGeometry(geometry, {pointRadius: 3}, "blah_4000");
t.eq(drawCircleCalled, true, "drawCircle called on drawGeometry for a point geometry.")
t.ok(node.parentNode != r.root, "circle will not be drawn when coordinates are outside the valid range");
}
function test_SVG_drawlinestring(t) {
@@ -181,7 +189,7 @@
r.getComponentsString = function(c) {
g_GetString = true;
g_Components = c;
return "bar";
return {path: "bar", complete: true};
}
r.drawLineString(node, geometry);
@@ -210,7 +218,7 @@
r.getComponentsString = function(c) {
g_GetString = true;
g_Components = c;
return "bar";
return {path: "bar", complete: true};
}
r.drawLinearRing(node, geometry);
@@ -255,8 +263,7 @@
r.getShortString = function(c) {
return false;
}
r.drawPolygon(node, geometry);
t.eq(node.getAttributeNS(null, "d"), "", "d attribute is empty if one linearRing cannot be drawn");
t.eq(r.drawPolygon(node, geometry), false, "drawPolygon returns false if one linearRing cannot be drawn");
}
function test_SVG_drawrectangle(t) {
@@ -319,8 +326,8 @@
r.getShortString = function(c) {
return false;
}
r.drawSurface(node, geometry);
t.eq(node.getAttributeNS(null, "d"), "", "d attribute is empty if one linearRing cannot be drawn");
t.eq(r.drawSurface(node, geometry), false, "drawSurface returns false if one linearRing cannot be drawn");
}
function test_SVG_getcomponentsstring(t) {
@@ -340,7 +347,7 @@
return p;
};
var string = OpenLayers.Renderer.SVG.prototype.getComponentsString(components);
var string = OpenLayers.Renderer.SVG.prototype.getComponentsString(components).path;
t.eq(string, "foo,bar", "returned string is correct");
OpenLayers.Renderer.SVG.prototype.getShortString =
@@ -423,6 +430,35 @@
t.eq(r.dashStyle({strokeWidth: 1, strokeDashstyle: "dashdot"}, 1), "4,4,1,4", "dashdot dasharray created correctly");
t.eq(r.dashStyle({strokeWidth: 1, strokeDashstyle: "longdashdot"}, 1), "8,4,1,4", "dashdot dasharray created correctly");
}
function test_svg_clipline(t) {
if (!OpenLayers.Renderer.SVG.prototype.supported()) {
t.plan(0);
return;
}
t.plan(1);
var r = new OpenLayers.Renderer.SVG(document.body);
r.setSize(new OpenLayers.Size(0, 0));
r.map = {
getResolution: function() {
return 0.5;
}
}
r.setExtent(new OpenLayers.Bounds(0, 0, 0, 0));
var geometry = new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(0, -5000),
new OpenLayers.Geometry.Point(10000, 0),
new OpenLayers.Geometry.Point(0, 5000)
]);
var node = document.createElement('div');
r.drawLineString(node, geometry);
t.eq(node.getAttribute("points"), "0,10000,15000,2500,15000,-2500,0,-10000", "Geometry correctly clipped at inValidRange bounds");
}
</script>
</head>

View File

@@ -0,0 +1,123 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SVG inValidRange Test Case</title><link
href="../../theme/default/style.css"
rel="stylesheet" type="text/css">
<style>
#map {
width: 512px;
height: 512px;
border: 1px solid #4B3624;
background: White;
}
.olControlAttribution { bottom: 0px!important }
</style>
<script src="../../lib/OpenLayers.js"
type="text/javascript"></script>
<script type="text/javascript">var map;
// avoid pink tiles
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
OpenLayers.Util.onImageLoadErrorColor = "transparent";
var vectorLayer;
var markerLayer, boxes, newPoint;
function init(){
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
numZoomLevels: 19,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
20037508, 20037508.34)
};
map = new OpenLayers.Map('map', options);
map.addControl(new OpenLayers.Control.MousePosition());
vectorLayer = new OpenLayers.Layer.Vector("Trails", {isBaseLayer: true});
markerLayer = new OpenLayers.Layer.Markers("WayPoints");
map.addLayers([vectorLayer,markerLayer]);
var style_trail = OpenLayers.Util.extend({},
OpenLayers.Feature.Vector.style['default']);
style_trail.strokeColor = "green";
style_trail.strokeWidth = 5;
var pointList = [];
newPoint = new OpenLayers.Geometry.Point(-13653735.8487833,5726045.3578081);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653731.3960036,5726056.5070679);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653730.8394062,5726044.7207079);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653743.1958697,5726043.9243328);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653754.1051798,5726046.9505586);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653760.4503907,5726056.5070679);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653767.4635187,5726065.5857612);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653830.136392,5726052.2066375);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-13653846.5003571,5726042.3315828);
pointList.push(newPoint);
var lineFeature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LineString(pointList));
lineFeature.fid = 52730;
vectorLayer.addFeatures(lineFeature);
pointList = [];
newPoint = new OpenLayers.Geometry.Point(-12250153.3626406,4852001.6114048);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-12194315.5060664,4800503.5113048);
pointList.push(newPoint);
newPoint = new OpenLayers.Geometry.Point(-12180445.0975155,4873109.008858);
pointList.push(newPoint);
lineFeature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LineString(pointList),null,style_trail);
lineFeature.fid = 52751;
vectorLayer.addFeatures([lineFeature]);
var size = new OpenLayers.Size(15, 15);
var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
var icon = new OpenLayers.Icon('../../img/marker.png', size, offset);
markerLayer.addMarker(new OpenLayers.Marker(
new OpenLayers.LonLat((newPoint.x + 400), (newPoint.y - 400)), icon));
map.setCenter(new OpenLayers.LonLat(newPoint.x, newPoint.y), 13)
}
function zoomToScale(zoom) {
if (zoom == 8) map.zoomToScale(3385.5001275);
else if(zoom == 7) map.zoomToScale(6771.000255);
else if (zoom == 6) map.zoomToScale(13542);
else if (zoom == 5) map.zoomToScale(27084.001020);
else if (zoom == 4) map.zoomToScale(54168.001020);
else if (zoom == 3) map.zoomToScale(108337);
else if (zoom == 2) map.zoomToScale(3466752.1306573446);
else if (zoom == 1) map.zoomToScale(13867008.522629378);
else if (zoom == 0) map.zoomToScale(55468034.09051751);
}
</script>
</head>
<body onLoad="init()">
<h1 id="title">SVG inValidRange Clipping Test Case</h1>
<p>Behavior before fixing #1631: Push Zoom 5. You see lines. Push
Zoom 6. No lines.</p>
<div id="map">
</div>
<button onClick="zoomToScale(5);">Zoom 5</button>
<button onClick="zoomToScale(6);">Zoom 6</button>
<button onClick="zoomToScale(7);">Zoom 7</button>
<button onClick="zoomToScale(8);">Zoom 8</button>
</body>
</html>

View File

@@ -0,0 +1,58 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="../../theme/default/style.css" type="text/css" />
<style type="text/css">
#map {
width: 512px;
height: 512px;
border: 1px solid gray;
}
</style>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, point;
function init(){
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
maxResolution: 20, //0.07464553542137146,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
20037508, 20037508.34)
};
map = new OpenLayers.Map('map', options);
var vector = new OpenLayers.Layer.Vector(
"Vectors",
{isBaseLayer: true}
);
map.addLayer(vector);
var x = -20000;//4.33791754;
var y = 20000;
point = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(x, y)
);
map.addLayer(vector);
vector.addFeatures([point]);
map.setCenter(new OpenLayers.LonLat(0, 0), 5);
}
function pan(){
map.panTo(point.geometry.getBounds().getCenterLonLat());
}
</script>
</head>
<body onload="init()">
<h3 id="title">SVG inValidRange Redraw Test Case</h3>
<p>Before fixing #1631, after klicking Go! no point would have appeared. The Go! button
pans the map over a long distance. Before dragging, the point would have been
outside the valid range, and the pan operation would not have triggered the SVG
coordinate system to be recreated. The new vector rendering takes care of all this. </p>
<div id="map"></div>
<input type="button" value="Go!" onclick="pan();"></input>
</body>
</html>

View File

@@ -73,7 +73,7 @@
}
function vectorTestNew() {
vectorLayer.renderer.drawFeature = drawFeature;
vectorLayer.renderer.drawFeature = OpenLayers.Renderer[vectorLayer.renderer.CLASS_NAME.split(".")[2]].prototype.drawFeature;
console.time("addFeatures");
vectorLayer.addFeatures(features);
@@ -89,17 +89,25 @@
map.addControl(new OpenLayers.Control.MousePosition());
map.setCenter(new OpenLayers.LonLat(-22.5, -22.5), 3);
drawFeature = vectorLayer.renderer.drawFeature;
vectorLayer.events.register("featuresadded", this, nextRun);
features = new Array(100);
features = new Array(200);
var x, y
for (var i = 0; i < 100; i++) {
for (var i = 0; i < 200; i++) {
x = -Math.random()*45;
y = -Math.random()*45;
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
-Math.random()*5+x, -Math.random()*5+y),
new OpenLayers.Geometry.Point(
@@ -119,14 +127,16 @@
</script>
</head>
<body onload="init()">
<h1 id="title">Vector Features Performance Test</h1>
<h1 id="title">New Rendering - Vector Features Performance Test</h1>
<div id="map"></div>
<p>
This test examines if checking for a feature being inside the visible
extent before rendering it has an impact on performance. Make sure that
the Firebug console is visible when running this test to see the results.
extent before rendering it has an impact on performance. Open the Firebug
console after running this test (hit F12) to see the results.
<br/>
After the performance test, you can drag around the map to see how the new
vector rendering feels where features get rendered only when they are visible
inside the map extent.
</p>
</body>
</html>