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:
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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>
|
||||
|
||||
123
tests/manual/clip-features-svg.html
Normal file
123
tests/manual/clip-features-svg.html
Normal 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>
|
||||
58
tests/manual/pan-redraw-svg.html
Normal file
58
tests/manual/pan-redraw-svg.html
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user