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

@@ -106,6 +106,13 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* {Array(<OpenLayers.Feature.Vector>)}
*/
selectedFeatures: null,
/**
* Property: unrenderedFeatures
* {Object} hash of features, keyed by feature.id, that the renderer
* failed to draw
*/
unrenderedFeatures: null,
/**
* APIProperty: reportError
@@ -213,6 +220,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
this.features = [];
this.selectedFeatures = [];
this.unrenderedFeatures = {};
// Allow for custom layer behavior
if(this.strategies){
@@ -247,6 +255,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
this.destroyFeatures();
this.features = null;
this.selectedFeatures = null;
this.unrenderedFeatures = null;
if (this.renderer) {
this.renderer.destroy();
}
@@ -359,6 +368,8 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
*/
moveTo: function(bounds, zoomChanged, dragging) {
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
var coordSysUnchanged = true;
if (!dragging) {
this.renderer.root.style.visibility = "hidden";
@@ -366,7 +377,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
var extent = this.map.getExtent();
this.renderer.setExtent(extent);
coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
this.renderer.root.style.visibility = "visible";
@@ -376,17 +387,33 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
this.div.scrollLeft = this.div.scrollLeft;
}
if(!zoomChanged && coordSysUnchanged) {
var unrenderedFeatures = {};
for(var i in this.unrenderedFeatures) {
var feature = this.unrenderedFeatures[i];
if(!this.drawFeature(feature)) {
unrenderedFeatures[i] = feature;
}
}
this.unrenderedFeatures = unrenderedFeatures;
}
}
if (!this.drawn || zoomChanged) {
if (!this.drawn || zoomChanged || !coordSysUnchanged) {
this.unrenderedFeatures = {};
this.drawn = true;
var feature;
for(var i=0, len=this.features.length; i<len; i++) {
if (i != (this.features.length - 1)) {
this.renderer.locked = true;
} else {
this.renderer.locked = false;
}
this.drawFeature(this.features[i]);
feature = this.features[i];
if (!this.drawFeature(feature)) {
this.unrenderedFeatures[feature.id] = feature;
};
}
}
},
@@ -438,7 +465,9 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
if (this.drawn) {
this.drawFeature(feature);
if(!this.drawFeature(feature)) {
this.unrenderedFeatures[feature.id] = feature;
}
}
if (notify) {
@@ -488,6 +517,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
var feature = features[i];
delete this.unrenderedFeatures[feature.id];
if (notify) {
this.events.triggerEvent("beforefeatureremoved", {
@@ -553,6 +583,10 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {Object} Symbolizer hash or {String} renderIntent
*
* Returns:
* {Boolean} true if the renderer was able to draw the feature, false
* otherwise
*/
drawFeature: function(feature, style) {
if (typeof style != "object") {
@@ -564,7 +598,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
}
this.renderer.drawFeature(feature, style);
return this.renderer.drawFeature(feature, style);
},
/**

View File

@@ -103,13 +103,19 @@ OpenLayers.Renderer = OpenLayers.Class({
* Resolution has probably changed, so we nullify the resolution
* cache (this.resolution) -- this way it will be re-computed when
* next it is needed.
* We nullify the resolution cache (this.resolution) if resolutionChanged
* is set to true - this way it will be re-computed on the next
* getResolution() request.
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*/
setExtent: function(extent) {
setExtent: function(extent, resolutionChanged) {
this.extent = extent.clone();
this.resolution = null;
if (resolutionChanged) {
this.resolution = null;
}
},
/**
@@ -148,14 +154,21 @@ OpenLayers.Renderer = OpenLayers.Class({
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {<Object>}
* style - {<Object>}
*
* Returns:
* {Boolean} true if the feature has been drawn completely, false if not,
* undefined if the feature had no geometry
*/
drawFeature: function(feature, style) {
if(style == null) {
style = feature.style;
}
if (feature.geometry) {
this.drawGeometry(feature.geometry, style, feature.id);
if (!feature.geometry.getBounds().intersectsBounds(this.extent)) {
style = {display: "none"};
}
return this.drawGeometry(feature.geometry, style, feature.id);
}
},
@@ -223,4 +236,4 @@ OpenLayers.Renderer = OpenLayers.Class({
eraseGeometry: function(geometry) {},
CLASS_NAME: "OpenLayers.Renderer"
});
});

View File

@@ -450,26 +450,36 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {String}
*
* Returns:
* {Boolean} true if the geometry has been drawn completely; null if
* incomplete; false otherwise
*/
drawGeometry: function(geometry, style, featureId) {
var className = geometry.CLASS_NAME;
var rendered = true;
if ((className == "OpenLayers.Geometry.Collection") ||
(className == "OpenLayers.Geometry.MultiPoint") ||
(className == "OpenLayers.Geometry.MultiLineString") ||
(className == "OpenLayers.Geometry.MultiPolygon")) {
for (var i = 0, len=geometry.components.length; i<len; i++) {
this.drawGeometry(geometry.components[i], style, featureId);
rendered = rendered && this.drawGeometry(
geometry.components[i], style, featureId);
}
return;
return rendered;
};
rendered = false;
if (style.display != "none") {
if (style.backgroundGraphic) {
this.redrawBackgroundNode(geometry.id, geometry, style, featureId);
this.redrawBackgroundNode(geometry.id, geometry, style,
featureId);
}
this.redrawNode(geometry.id, geometry, style, featureId);
} else {
var node = OpenLayers.Util.getElement(geometry.id);
rendered = this.redrawNode(geometry.id, geometry, style,
featureId);
}
if (rendered == false) {
var node = document.getElementById(geometry.id);
if (node) {
if (node._style.backgroundGraphic) {
node.parentNode.removeChild(document.getElementById(
@@ -478,6 +488,7 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
node.parentNode.removeChild(node);
}
}
return rendered;
},
/**
@@ -488,6 +499,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {String}
*
* Returns:
* {Boolean} true if the complete geometry could be drawn, null if parts of
* the geometry could not be drawn, false otherwise
*/
redrawNode: function(id, geometry, style, featureId) {
// Get the node if it's already on the map.
@@ -508,7 +523,13 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
newNode._geometry = geometry;
newNode._geometryClass = geometry.CLASS_NAME;
newNode._style = style;
newNode = this.drawGeometryNode(newNode, geometry, style);
var drawResult = this.drawGeometryNode(newNode, geometry, style);
if(drawResult === false) {
return false;
}
newNode = drawResult.node;
// Insert the node into the indexer so it can show us where to
// place it. Note that this operation is O(log(n)). If there's a
@@ -522,7 +543,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
this.root.appendChild(newNode);
}
this.postDraw(newNode);
this.postDraw(newNode);
return drawResult.complete;
},
/**
@@ -540,6 +563,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {String}
*
* Returns:
* {Boolean} true if the complete geometry could be drawn, null if parts of
* the geometry could not be drawn, false otherwise
*/
redrawBackgroundNode: function(id, geometry, style, featureId) {
var backgroundStyle = OpenLayers.Util.extend({}, style);
@@ -556,7 +583,7 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
backgroundStyle.backgroundYOffset = null;
backgroundStyle.backgroundGraphicZIndex = null;
this.redrawNode(
return this.redrawNode(
id + this.BACKGROUND_ID_SUFFIX,
geometry,
backgroundStyle,
@@ -574,6 +601,11 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
*
* Returns:
* {Object} a hash with properties "node" (the drawn node) and "complete"
* (null if parts of the geometry could not be drawn, false if nothing
* could be drawn)
*/
drawGeometryNode: function(node, geometry, style) {
style = style || node._style;
@@ -583,25 +615,26 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
'isFilled': true,
'isStroked': !!style.strokeWidth
};
var drawn;
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
this.drawPoint(node, geometry);
drawn = this.drawPoint(node, geometry);
break;
case "OpenLayers.Geometry.LineString":
options.isFilled = false;
this.drawLineString(node, geometry);
drawn = this.drawLineString(node, geometry);
break;
case "OpenLayers.Geometry.LinearRing":
this.drawLinearRing(node, geometry);
drawn = this.drawLinearRing(node, geometry);
break;
case "OpenLayers.Geometry.Polygon":
this.drawPolygon(node, geometry);
drawn = this.drawPolygon(node, geometry);
break;
case "OpenLayers.Geometry.Surface":
this.drawSurface(node, geometry);
drawn = this.drawSurface(node, geometry);
break;
case "OpenLayers.Geometry.Rectangle":
this.drawRectangle(node, geometry);
drawn = this.drawRectangle(node, geometry);
break;
default:
break;
@@ -612,7 +645,14 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
//set style
//TBD simplify this
return this.setStyle(node, style, options, geometry);
if (drawn != false) {
return {
node: this.setStyle(node, style, options, geometry),
complete: drawn
};
} else {
return false;
}
},
/**
@@ -634,6 +674,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the point
*/
drawPoint: function(node, geometry) {},
@@ -646,6 +689,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components of
* the linestring, or false if nothing could be drawn
*/
drawLineString: function(node, geometry) {},
@@ -658,6 +705,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the linear ring, or false if nothing could be drawn
*/
drawLinearRing: function(node, geometry) {},
@@ -670,6 +721,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the polygon, or false if nothing could be drawn
*/
drawPolygon: function(node, geometry) {},
@@ -682,6 +737,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the rectangle
*/
drawRectangle: function(node, geometry) {},
@@ -694,6 +752,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the circle
*/
drawCircle: function(node, geometry) {},
@@ -706,6 +767,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the surface
*/
drawSurface: function(node, geometry) {},

View File

@@ -31,14 +31,14 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* {Integer} Firefox has a limitation where values larger or smaller than
* about 15000 in an SVG document lock the browser up. This
* works around it.
*/
*/
MAX_PIXEL: 15000,
/**
* Property: localResolution
* {Float}
/**
* Property: translationParameters
* {Object} Hash with "x" and "y" properties
*/
localResolution: null,
translationParameters: null,
/**
* Property: symbolSize
@@ -58,6 +58,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments);
this.translationParameters = {x: 0, y: 0};
},
/**
@@ -86,16 +87,20 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* See #669 for more information
*
* Parameters:
* x - {Integer}
* y - {Integer}
* x - {Integer}
* y - {Integer}
* xyOnly - {Boolean} whether or not to just check for x and y, which means
* to not take the current translation parameters into account if true.
*
* Returns:
* {Boolean} Whether or not the 'x' and 'y' coordinates are in the
* valid range.
*/
inValidRange: function(x, y) {
return (x >= -this.MAX_PIXEL && x <= this.MAX_PIXEL &&
y >= -this.MAX_PIXEL && y <= this.MAX_PIXEL);
inValidRange: function(x, y, xyOnly) {
var left = x + (xyOnly ? 0 : this.translationParameters.x);
var top = y + (xyOnly ? 0 : this.translationParameters.y);
return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
},
/**
@@ -103,39 +108,66 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*
* Returns:
* {Boolean} true to notify the layer that the new extent does not exceed
* the coordinate range, and the features will not need to be redrawn.
* False otherwise.
*/
setExtent: function(extent) {
setExtent: function(extent, resolutionChanged) {
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
arguments);
var resolution = this.getResolution();
var left = -extent.left / resolution;
var top = extent.top / resolution;
// If the resolution has changed, start over changing the corner, because
// the features will redraw.
if (!this.localResolution || resolution != this.localResolution) {
this.left = -extent.left / resolution;
this.top = extent.top / resolution;
}
var left = 0;
var top = 0;
if (resolutionChanged) {
this.left = left;
this.top = top;
// Set the viewbox
var extentString = "0 0 " + this.size.w + " " + this.size.h;
// If the resolution has not changed, we already have features, and we need
// to adjust the viewbox to fit them.
if (this.localResolution && resolution == this.localResolution) {
left = (this.left) - (-extent.left / resolution);
top = (this.top) - (extent.top / resolution);
}
// Store resolution for use later.
this.localResolution = resolution;
// Set the viewbox -- the left/top will be pixels-dragged-since-res change,
// the width/height will be pixels.
var extentString = left + " " + top + " " +
this.size.w + " " + this.size.h;
//var extentString = extent.left / resolution + " " + -extent.top / resolution + " " +
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
this.translate(0, 0);
return true;
} else {
var inRange = this.translate(left - this.left, top - this.top);
if (!inRange) {
// recenter the coordinate system
this.setExtent(extent, true);
}
return inRange;
}
},
/**
* Method: translate
* Transforms the SVG coordinate system
*
* Parameters:
* x - {Float}
* y - {Float}
*
* Returns:
* {Boolean} true if the translation parameters ar in the valid coordinates
* range, false otherwise.
*/
translate: function(x, y) {
if (!this.inValidRange(x, y, true)) {
return false;
} else {
var transformString = "";
if (x || y) {
transformString = "translate(" + x + "," + y + ")";
}
this.root.setAttributeNS(null, "transform", transformString);
this.translationParameters = {x: x, y: y};
return true;
}
},
/**
@@ -413,9 +445,12 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the point
*/
drawPoint: function(node, geometry) {
this.drawCircle(node, geometry, 1);
return this.drawCircle(node, geometry, 1);
},
/**
@@ -426,6 +461,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* radius - {Float}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the circle
*/
drawCircle: function(node, geometry, radius) {
var resolution = this.getResolution();
@@ -436,10 +474,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
node.setAttributeNS(null, "cx", x);
node.setAttributeNS(null, "cy", y);
node.setAttributeNS(null, "r", radius);
return node;
} else {
node.setAttributeNS(null, "cx", "");
node.setAttributeNS(null, "cy", "");
node.setAttributeNS(null, "r", 0);
return false;
}
},
@@ -451,23 +488,41 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components of
* the linestring, or false if nothing could be drawn
*/
drawLineString: function(node, geometry) {
node.setAttributeNS(null, "points",
this.getComponentsString(geometry.components));
var componentsResult = this.getComponentsString(geometry.components);
if (componentsResult.path) {
node.setAttributeNS(null, "points", componentsResult.path);
return (componentsResult.complete ? node : null);
} else {
return false;
}
},
/**v
/**
* Method: drawLinearRing
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the linear ring, or false if nothing could be drawn
*/
drawLinearRing: function(node, geometry) {
node.setAttributeNS(null, "points",
this.getComponentsString(geometry.components));
var componentsResult = this.getComponentsString(geometry.components);
if (componentsResult.path) {
node.setAttributeNS(null, "points", componentsResult.path);
return (componentsResult.complete ? node : null);
} else {
return false;
}
},
/**
@@ -477,28 +532,35 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the polygon, or false if nothing could be drawn
*/
drawPolygon: function(node, geometry) {
var d = "";
var draw = true;
var complete = true;
var linearRingResult, path;
for (var j=0, len=geometry.components.length; j<len; j++) {
var linearRing = geometry.components[j];
d += " M";
for (var i=0, ilen=linearRing.components.length; i<ilen; i++) {
var component = this.getShortString(linearRing.components[i]);
if (component) {
d += " " + component;
} else {
draw = false;
}
linearRingResult = this.getComponentsString(
geometry.components[j].components, " ");
path = linearRingResult.path;
if (path) {
d += " " + path;
complete = linearRingResult.complete && complete;
} else {
draw = false;
}
}
d += " z";
if (draw) {
node.setAttributeNS(null, "d", d);
node.setAttributeNS(null, "fill-rule", "evenodd");
return complete ? node : null;
} else {
node.setAttributeNS(null, "d", "");
return false;
}
},
@@ -509,6 +571,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the rectangle
*/
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
@@ -520,11 +585,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
node.setAttributeNS(null, "y", y);
node.setAttributeNS(null, "width", geometry.width / resolution);
node.setAttributeNS(null, "height", geometry.height / resolution);
return node;
} else {
node.setAttributeNS(null, "x", "");
node.setAttributeNS(null, "y", "");
node.setAttributeNS(null, "width", 0);
node.setAttributeNS(null, "height", 0);
return false;
}
},
@@ -535,6 +598,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the surface
*/
drawSurface: function(node, geometry) {
@@ -559,8 +625,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
d += " Z";
if (draw) {
node.setAttributeNS(null, "d", d);
return node;
} else {
node.setAttributeNS(null, "d", "");
return false;
}
},
@@ -569,19 +636,93 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*
* Parameters:
* components - {Array(<OpenLayers.Geometry.Point>)} Array of points
* separator - {String} character between coordinate pairs. Defaults to ","
*
* Returns:
* {Object} hash with properties "path" (the string created from the
* components and "complete" (false if the renderer was unable to
* draw all components)
*/
getComponentsString: function(components) {
getComponentsString: function(components, separator) {
var renderCmp = [];
var complete = true;
var len = components.length;
var strings = [];
for(var i=0, len=components.length; i<len; i++) {
var component = this.getShortString(components[i]);
if (component) {
strings.push(component);
var str, component, j;
for(var i=0; i<len; i++) {
component = components[i];
renderCmp.push(component);
str = this.getShortString(component);
if (str) {
strings.push(str);
} else {
// The current component is outside the valid range. Let's
// see if the previous or next component is inside the range.
// If so, add the coordinate of the intersection with the
// valid range bounds.
if (i > 0) {
if (this.getShortString(components[i + 1])) {
strings.push(this.clipLine(components[i],
components[i-1]));
}
}
if (i < len - 1) {
if (this.getShortString(components[i + 1])) {
strings.push(this.clipLine(components[i],
components[i+1]));
}
}
complete = false;
}
}
return strings.join(",");
return {
path: strings.join(separator || ","),
complete: complete
};
},
/**
* Method: clipLine
* Given two points (one inside the valid range, and one outside),
* clips the line betweeen the two points so that the new points are both
* inside the valid range.
*
* Parameters:
* badComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
* invalid point
* goodComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
* valid point
* Returns
* {String} the SVG coordinate pair of the clipped point (like
* getShortString), or an empty string if both passed componets are at
* the same point.
*/
clipLine: function(badComponent, goodComponent) {
if (goodComponent.equals(badComponent)) {
return "";
}
var resolution = this.getResolution();
var maxX = this.MAX_PIXEL - this.translationParameters.x;
var maxY = this.MAX_PIXEL - this.translationParameters.y;
var x1 = goodComponent.x / resolution + this.left;
var y1 = this.top - goodComponent.y / resolution;
var x2 = badComponent.x / resolution + this.left;
var y2 = this.top - badComponent.y / resolution;
var k;
if (x2 < -maxX || x2 > maxX) {
k = (y2 - y1) / (x2 - x1);
x2 = x2 < 0 ? -maxX : maxX;
y2 = y1 + (x2 - x1) * k;
}
if (y2 < -maxY || y2 > maxY) {
k = (x2 - x1) / (y2 - y1);
y2 = y2 < 0 ? -maxY : maxY;
x2 = x1 + (y2 - y1) * k;
}
return x2 + "," + y2;
},
/**
* Method: getShortString
*
@@ -589,7 +730,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* point - {<OpenLayers.Geometry.Point>}
*
* Returns:
* {String}
* {String} or false if point is outside the valid range
*/
getShortString: function(point) {
var resolution = this.getResolution();

View File

@@ -79,8 +79,13 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
* resolutionChanged - {Boolean}
*
* Returns:
* {Boolean} true to notify the layer that the new extent does not exceed
* the coordinate range, and the features will not need to be redrawn.
*/
setExtent: function(extent) {
setExtent: function(extent, resolutionChanged) {
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
arguments);
var resolution = this.getResolution();
@@ -95,6 +100,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
// flip the VML display Y axis upside down so it
// matches the display Y axis of the map
this.root.style.flip = "y";
return true;
},
@@ -569,23 +576,6 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
return this.nodeFactory(this.container.id + "_root", "olv:group");
},
/**
* Method: drawFeature
* Overrides the superclass's drawFeature method to take care of features
* that are outside the viewport.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {<Object>}
*/
drawFeature: function(feature, style) {
if (!feature.geometry.getBounds().intersectsBounds(this.extent)) {
style = {display: "none"};
}
OpenLayers.Renderer.Elements.prototype.drawFeature.apply(this,
[feature, style]);
},
/**************************************
* *
* GEOMETRY DRAWING FUNCTIONS *
@@ -599,9 +589,12 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the point could not be drawn
*/
drawPoint: function(node, geometry) {
this.drawCircle(node, geometry, 1);
return this.drawCircle(node, geometry, 1);
},
/**
@@ -613,6 +606,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* radius - {float}
*
* Returns:
* {DOMElement} or false if the circle could not ne drawn
*/
drawCircle: function(node, geometry, radius) {
if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
@@ -625,7 +621,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
node.style.width = diameter + "px";
node.style.height = diameter + "px";
return node;
}
return false;
},
@@ -636,9 +634,12 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement}
*/
drawLineString: function(node, geometry) {
this.drawLine(node, geometry, false);
return this.drawLine(node, geometry, false);
},
/**
@@ -648,9 +649,12 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement}
*/
drawLinearRing: function(node, geometry) {
this.drawLine(node, geometry, true);
return this.drawLine(node, geometry, true);
},
/**
@@ -661,6 +665,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* closeLine - {Boolean} Close the line? (make it a ring?)
*
* Returns:
* {DOMElement}
*/
drawLine: function(node, geometry, closeLine) {
@@ -679,6 +686,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
}
var end = (closeLine) ? " x e" : " e";
node.path = "m" + parts.join("") + end;
return node;
},
/**
@@ -688,6 +696,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement}
*/
drawPolygon: function(node, geometry) {
this.setNodeDimension(node, geometry);
@@ -713,6 +724,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
}
path.push("e");
node.path = path.join("");
return node;
},
/**
@@ -722,6 +734,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement}
*/
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
@@ -730,6 +745,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
node.style.top = geometry.y/resolution + "px";
node.style.width = geometry.width/resolution + "px";
node.style.height = geometry.height/resolution + "px";
return node;
},
/**
@@ -738,6 +755,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement}
*/
drawSurface: function(node, geometry) {
@@ -761,6 +781,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
path.push(" x e");
node.path = path.join("");
return node;
},
/**