/* Copyright (c) 2009 Arnaud Renevier, Inc, published under the modified BSD
* license. */
+/*
+ * With canvas rendering engine, externalgraphics are drawn by loading and
+ * Image javascript object and drawing it with drawImage once it has been
+ * loaded. If matching feature is deleted while image is loading, redraw
+ * function will be called before drawImage and therefore, feature is removed,
+ * but image is still drawn on the screen. We fix it with locks: when an image is
+ * loading, we defer redraw method.
+ */
+OpenLayers.Renderer.Canvas.prototype = OpenLayers.Util.extend({
+ needsRedraw: false,
+ imagesLoading: 0
+}, OpenLayers.Renderer.Canvas.prototype);
+OpenLayers.Renderer.Canvas.prototype.oldRedraw = OpenLayers.Renderer.Canvas.prototype.redraw;
+OpenLayers.Renderer.Canvas.prototype.redraw = function() {
+ if (this.imagesLoading > 0) {
+ this.needsRedraw = true;
+ return;
+ }
+ OpenLayers.Renderer.Canvas.prototype.oldRedraw.apply(this, arguments);
+}
+OpenLayers.Renderer.Canvas.prototype.drawExternalGraphic = function(pt, style) {
+ var img = new Image();
+ img.src = style.externalGraphic;
+
+ if(style.graphicTitle) {
+ img.title=style.graphicTitle;
+ }
+
+ var width = style.graphicWidth || style.graphicHeight;
+ var height = style.graphicHeight || style.graphicWidth;
+ width = width ? width : style.pointRadius*2;
+ height = height ? height : style.pointRadius*2;
+ var xOffset = (style.graphicXOffset != undefined) ?
+ style.graphicXOffset : -(0.5 * width);
+ var yOffset = (style.graphicYOffset != undefined) ?
+ style.graphicYOffset : -(0.5 * height);
+ var opacity = style.graphicOpacity || style.fillOpacity;
+
+ var context = { img: img,
+ x: (pt[0]+xOffset),
+ y: (pt[1]+yOffset),
+ width: width,
+ height: height,
+ canvas: this.canvas };
+
+ var self = this;
+ this.imagesLoading++;
+ img.onerror = function() {
+ self.imagesLoading--;
+ if ((self.imagesLoading == 0) && (self.needsRedraw)) {
+ self.needsRedraw = false;
+ self.redraw();
+ }
+ }
+ img.onload = OpenLayers.Function.bind( function() {
+ self.imagesLoading--;
+ if ((self.imagesLoading == 0) && (self.needsRedraw)) {
+ self.needsRedraw = false;
+ self.redraw();
+ } else {
+ this.canvas.drawImage(this.img, this.x,
+ this.y, this.width, this.height);
+ }
+ }, context);
+}
+
+
OpenLayers.Control.SypAttribution = OpenLayers.Class (OpenLayers.Control.Attribution, {
updateAttribution: function() {
- var attributions = [SypStrings.propulsedByLink];
+ var attributions = [SypStrings.poweredByLink];
if (this.map && this.map.layers) {
for(var i=0, len=this.map.layers.length; i<len; i++) {
var layer = this.map.layers[i];
createDataLayer: function(map) {
var defaultStyle = new OpenLayers.Style({
externalGraphic: this.Markers.ICON,
- graphicHeight: "${height}"
+ graphicHeight: "${height}",
+ label: "${label}",
+ fontColor: "white",
+ fontWeight: "bold"
}, {
context: {
height: function(feature) {
var defaultHeight = SYP.Markers.HEIGHT || 32;
var increase = 4 * (feature.attributes.count - 1);
return Math.min(defaultHeight + increase, 50);
+ },
+ label: function(feature) {
+ var renderer = feature.layer.renderer;
+ if (renderer.CLASS_NAME == "OpenLayers.Renderer.Canvas") {
+ return ""; // canvas backend cannot draw text above an external Image
+ }
+ return (feature.attributes.count > 1) ? feature.attributes.count: "";
}
}
});
}
var map = this.map;
- if (map.getControlsByClass("OpenLayers.Control.ArgParser")[0].lat
- == undefined) { // map center was not set in ArgParser control.
+ if (map.getControlsByClass("OpenLayers.Control.ArgParser")[0].center
+ == null) { // map center was not set in ArgParser control.
var orig = this.Utils.mbr (this.dataLayer);
var centerBounds = new OpenLayers.Bounds();
}
},
+ onZoomClusterEnd: function(arg) {
+ var map = arg.object;
+ var point = new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat);
+ var center = map.getCenter();
+ for (var i = this.layer.features.length; i-->0;) {
+ var feature = this.layer.features[i];
+ if (feature.geometry.equals(point) &&
+ (feature.attributes.count == this.count)) {
+ var self = this;
+ window.setTimeout(function() { map.setCenter(self.lonlat, map.zoom + 1)}, 500);
+ return;
+ }
+ }
+ SYP.selectControl.activate();
+ map.events.unregister("zoomend", this, SYP.onZoomClusterEnd);
+ },
+
onFeatureSelect: function(feature) {
var map = feature.layer.map;
+
if (feature.attributes.count > 1) {
this.unselect(feature);
var lonlat = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y);
+ var args = {
+ lonlat: lonlat,
+ layer: feature.layer,
+ count: feature.attributes.count
+ }
+ map.events.register("zoomend", args, SYP.onZoomClusterEnd);
+ SYP.selectControl.deactivate();
map.setCenter(lonlat, map.zoom + 1);
return;
}
}
var contentHTML;
if (feature.cluster[0].attributes.name) {
+ // escaping name is necessary because it's not enclosed in another html tag.
contentHTML = "<h2>" +
- feature.cluster[0].attributes.name +
+ SYP.Utils.escapeHTML(feature.cluster[0].attributes.name) +
"</h2>" +
feature.cluster[0].attributes.description;
} else {
},
showBigImage: function (href) {
- try {
- document.getElementById('bigimg_container').style.display = "table";
- } catch(e) {
+ if (OpenLayers.Util.getBrowserName() == "msie") {
document.getElementById('bigimg_container').style.display = "block";
+ } else {
+ document.getElementById('bigimg_container').style.display = "table";
}
+
var maxHeight = document.body.clientHeight * 0.9;
var maxWidth = document.body.clientWidth * 0.9;
document.getElementById('bigimg').style.height = "";
}
}
+ var offsetTop = this.offsetTop;
+ var offsetLeft = this.offsetLeft;
+ var par = this.offsetParent;
+ var ismsie = OpenLayers.Util.getBrowserName() == "msie";
+ while (par && !ismsie) {
+ offsetTop += par.offsetTop;
+ offsetLeft += par.offsetLeft;
+ par = par.offsetParent;
+ }
var icon = document.getElementById('bigimg_close');
- icon.style.top = this.offsetTop;
- icon.style.left = this.offsetLeft + this.clientWidth - icon.clientWidth;
+ icon.style.top = offsetTop;
+ icon.style.left = offsetLeft + this.clientWidth - icon.clientWidth;
};
document.getElementById('bigimg').src = href;
}
div.style.display = "block";
div.appendChild(textNode);
+ },
+
+ escapeHTML: function (str) {
+ if (!str) {
+ return "";
+ }
+ return str.
+ replace(/&/gm, '&').
+ replace(/'/gm, ''').
+ replace(/"/gm, '"').
+ replace(/>/gm, '>').
+ replace(/</gm, '<');
}
}
};
// least as big as content. To achieve that, we need to override
// OpenLayers.Popup.Anchored.prototype.updateSize to modify it slightly.
OpenLayers.Popup.Anchored.prototype.updateSize = function() {
- // determine actual render dimensions of the contents by putting its
- // contents into a fake contentDiv (for the CSS) and then measuring it
- var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" +
- this.contentDiv.innerHTML +
- "</div>";
-
- var containerElement = (this.map) ? this.map.layerContainerDiv
- : document.body;
- var realSize = OpenLayers.Util.getRenderedDimensions(
- preparedHTML, null, {
- displayClass: this.displayClass,
- containerElement: containerElement
+ var self = this;
+
+ window.setTimeout(function() { // timeout added by SYP
+
+ // determine actual render dimensions of the contents by putting its
+ // contents into a fake contentDiv (for the CSS) and then measuring it
+ var preparedHTML = "<div class='" + self.contentDisplayClass+ "'>" +
+ self.contentDiv.innerHTML +
+ "</div>";
+
+ var containerElement = (self.map) ? self.map.layerContainerDiv
+ : document.body;
+ var realSize = OpenLayers.Util.getRenderedDimensions(
+ preparedHTML, null, {
+ displayClass: self.displayClass,
+ containerElement: containerElement
+ }
+ );
+
+ /*
+ * XXX: next four lines are added by SYP!
+ */
+ if (self.contentDiv) {
+ realSize.w = Math.max (realSize.w, self.contentDiv.scrollWidth);
+ realSize.h = Math.max (realSize.h, self.contentDiv.scrollHeight);
}
- );
-
- /*
- * XXX: next four lines are added by SYP!
- */
- if (this.contentDiv) {
- realSize.w = Math.max (realSize.w, this.contentDiv.scrollWidth);
- realSize.h = Math.max (realSize.h, this.contentDiv.scrollHeight);
- }
- // is the "real" size of the div is safe to display in our map?
- var safeSize = this.getSafeContentSize(realSize);
+ // is the "real" size of the div is safe to display in our map?
+ var safeSize = self.getSafeContentSize(realSize);
- var newSize = null;
- if (safeSize.equals(realSize)) {
- //real size of content is small enough to fit on the map,
- // so we use real size.
- newSize = realSize;
+ var newSize = null;
+ if (safeSize.equals(realSize)) {
+ //real size of content is small enough to fit on the map,
+ // so we use real size.
+ newSize = realSize;
- } else {
+ } else {
- //make a new OL.Size object with the clipped dimensions
- // set or null if not clipped.
- var fixedSize = new OpenLayers.Size();
- fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
- fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
+ //make a new OL.Size object with the clipped dimensions
+ // set or null if not clipped.
+ var fixedSize = new OpenLayers.Size();
+ fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
+ fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
if (fixedSize.w && fixedSize.h) {
//content is too big in both directions, so we will use
// run getRenderedDimensions() again with a fixed dimension
var clippedSize = OpenLayers.Util.getRenderedDimensions(
preparedHTML, fixedSize, {
- displayClass: this.contentDisplayClass,
+ displayClass: self.contentDisplayClass,
containerElement: containerElement
}
);
// adjust for that.
//
var currentOverflow = OpenLayers.Element.getStyle(
- this.contentDiv, "overflow"
+ self.contentDiv, "overflow"
);
if ( (currentOverflow != "hidden") &&
(clippedSize.equals(safeSize)) ) {
}
}
- newSize = this.getSafeContentSize(clippedSize);
+ newSize = self.getSafeContentSize(clippedSize);
}
}
- this.setSize(newSize);
+ self.setSize(newSize);
+ }, 0);
}