Avoid VML rendering issues with zero area inner rings. We don't actually do an expensive area calculation, but just make sure that we have at least three distinct points. This version is slightly different from Tim's previous patch: it compares the VML path components rathter than the geometry components, which is less expensive and more reliable (because the VML path uses integers). p=tschaub,me r=me (closes #2876)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@10837 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2010-10-15 13:47:35 +00:00
parent 2176013e24
commit 12d3c86eb4
3 changed files with 40 additions and 32 deletions

View File

@@ -164,7 +164,7 @@
});
draw = new OpenLayers.Control.DrawFeature(
poly, OpenLayers.Handler.Polygon,
{displayClass: "olControlDrawFeaturePoint", title: "Draw Features"}
{displayClass: "olControlDrawFeaturePoint", title: "Draw Features", handlerOptions: {holeModifier: "altKey"}}
);
modify = new OpenLayers.Control.ModifyFeature(
poly, {displayClass: "olControlModifyFeature", title: "Modify Features"}

View File

@@ -751,21 +751,43 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var resolution = this.getResolution();
var path = [];
var linearRing, i, j, len, ilen, comp, x, y;
for (j = 0, len=geometry.components.length; j<len; j++) {
linearRing = geometry.components[j];
var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y;
for (j=0, jj=geometry.components.length; j<jj; j++) {
path.push("m");
for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
comp = linearRing.components[i];
points = geometry.components[j].components;
// we only close paths of interior rings with area
area = (j === 0);
first = null;
second = null;
for (i=0, ii=points.length; i<ii; i++) {
comp = points[i];
x = (comp.x / resolution - this.offset.x) | 0;
y = (comp.y / resolution - this.offset.y) | 0;
path.push(" " + x + "," + y);
pathComp = " " + x + "," + y;
path.push(pathComp)
if (i==0) {
path.push(" l");
}
if (!area) {
// IE improperly renders sub-paths that have no area.
// Instead of checking the area of every ring, we confirm
// the ring has at least three distinct points. This does
// not catch all non-zero area cases, but it greatly improves
// interior ring digitizing and is a minor performance hit
// when rendering rings with many points.
if (!first) {
first = pathComp;
} else if (first != pathComp) {
if (!second) {
second = pathComp;
} else if (second != pathComp) {
// stop looking
area = true;
}
}
}
}
path.push(" x ");
path.push(area ? " x " : " ");
}
path.push("e");
node.path = path.join("");

View File

@@ -305,7 +305,7 @@
return;
}
t.plan(2);
t.plan(3);
var r = new OpenLayers.Renderer.VML(document.body);
r.offset = {x: 0, y: 0};
@@ -318,30 +318,16 @@
var node = document.createElement('div');
var linearRing = {
components: [{
x: 1,
y: 2
},{
x: 3,
y: 4
}]
};
var linearRing2 = {
components: [{
x: 5,
y: 6
},{
x: 7,
y: 8
}]
};
var geometry = {
components: [linearRing, linearRing2]
};
var geometry = OpenLayers.Geometry.fromWKT(
"POLYGON((1 2, 3 4), (5 6, 7 8))"
);
r.drawPolygon(node, geometry, true);
t.ok(g_SetNodeDimension, "setNodeDimension is called");
t.eq(node.path, "m 2,4 l 6,8 x m 10,12 l 14,16 x e", "path attribute is correct");
t.eq(node.path, "m 2,4 l 6,8 2,4 x m 10,12 l 14,16 10,12 e", "path attribute is correct - inner ring has no area and is not closed");
geometry.components[1].addComponent(new OpenLayers.Geometry.Point(8, 7));
r.drawPolygon(node, geometry, true);
t.eq(node.path, "m 2,4 l 6,8 2,4 x m 10,12 l 14,16 16,14 10,12 x e", "path attribute is correct - inner ring has an area and is closed");
}
function test_VML_drawrectangle(t) {