/** * пользовательский интерфейс пакета openLayers * Package: openLayers * * @author Maltsev Alexey, Galkin Kirill * @version 0.3, 17.07.2009 * @since gefest v.1.0.0-RC1 * @copyright (c) 2009 2energies LTD */ /** * читалка "продвинутого" GeoRSS на основе штатной от OpenLayers */ OpenLayers.Format.GeoRSSAdv = OpenLayers.Class(OpenLayers.Format.GeoRSS, { createFeatureFromItem: function(item) { var geometry = this.createGeometryFromItem(item); /* Provide defaults for title and description */ var title = this.getChildValue(item, '*', 'title', this.featureTitle); var address = this.getChildValue(item, '*', 'address', this.featureTitle); /* First try RSS descriptions, then Atom summaries */ var description = this.getChildValue ( item, '*', 'description', this.getChildValue ( item, '*', 'content', this.getChildValue(item, '*', 'summary', this.featureDescription) ) ); /* If no link URL is found in the first child node, try the href attribute */ var link = this.getChildValue(item, '*', 'link'); if (!link) { try { link = this.getElementsByTagNameNS(item, '*', 'link')[0].getAttribute('href'); } catch(e) { link = null; } } var icon = this.getChildValue(item, '*', 'icon'); var thumbnail = this.getChildValue(item, '*', 'thumbnail'); var id = this.getChildValue(item, '*', 'id', null); var data = { 'title': title, 'description': description, 'address': address, 'link': link, 'icon': icon, 'thumbnail': thumbnail }; var feature = new OpenLayers.Feature.Vector(geometry, data); feature.fid = id; return feature; }, CLASS_NAME: 'OpenLayers.Format.GeoRSSAdv' }); /** * слой "продвинутого" GeoRSS на основе штатного от OpenLayers */ OpenLayers.Layer.GeoRSSAdv = OpenLayers.Class(OpenLayers.Layer.GeoRSS, { parseData: function(ajaxRequest) { var doc = ajaxRequest.responseXML; if (!doc || !doc.documentElement) doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText); if (this.useFeedTitle) { var name = null; try { name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue; } catch(e) { name = doc.getElementsByTagName('title')[0].firstChild.nodeValue; } if (name) this.setName(name); } var options = {}; OpenLayers.Util.extend(options, this.formatOptions); if (this.map && !this.projection.equals(this.map.getProjectionObject())) { options.externalProjection = this.projection; options.internalProjection = this.map.getProjectionObject(); } var format = new OpenLayers.Format.GeoRSSAdv(options); var features = format.read(doc); for (var i = 0, len = features.length; i < len; i++) { var data = {}; var feature = features[i]; // no Martini - no party if (!feature.geometry) continue; var title = feature.attributes.title ? feature.attributes.title : 'Untitled'; var description = feature.attributes.description ? feature.attributes.description : 'No description.'; var address = feature.attributes.address ? feature.attributes.address : 'Организация не оставила свой адрес'; var link = feature.attributes.link ? feature.attributes.link : ''; var location = feature.geometry.getBounds().getCenterLonLat(); var icon = feature.attributes.icon ? feature.attributes.icon : ''; var thumbnail = feature.attributes.thumbnail ? feature.attributes.thumbnail : '/upload/photo/l/null.jpg'; data.icon = icon ? this.getMarkerIcon(icon) : OpenLayers.Marker.defaultIcon(); data.popupSize = this.popupSize ? this.popupSize.clone() : new OpenLayers.Size(265, 123); /* Вычитаем размер margin сверху и снизу */ data.AncoredBubble = new OpenLayers.Popup.AnchoredBubble(null); if (title || address) { var adr = window.location.pathname.toString(); adr = adr.split('/'); adr = adr[1]; var lp = 'Перейти на страницу объекта'; if (adr == 'en') lp = 'Jump to page object'; if (adr == 'de') lp = 'Wechseln zu Seitenobjekt'; if (adr == 'fr') lp = 'Aller à la page objet'; if (adr == 'cn') lp = '跳轉到頁物件'; data.title = title; data.description = description; data.address = address; //for design var contentHTML = '
'; //var contentHTML = ''; //contentHTML += '
'; contentHTML += '
'; //изображение //if(thumbnail) contentHTML += ''; //заголовок if (link) contentHTML += ''; contentHTML += '

' + title + '

'; if (link) contentHTML += '
'; contentHTML += ''; if (link) contentHTML += ''+ lp +''; contentHTML += ''; contentHTML += ''; data['popupContentHTML'] = contentHTML; } var feature = new OpenLayers.Feature(this, location, data); this.features.push(feature); var marker = feature.createMarker(); marker.events.register('click', feature, this.markerClick); this.addMarker(marker); } this.events.triggerEvent('loadend'); }, markerClick: function(evt) { var sameMarkerClicked = (this == this.layer.selectedFeature); this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { this.layer.map.removePopup(this.layer.map.popups[i]); } if (!sameMarkerClicked) { var popup = this.createPopup(); /* Исправление для нормального отображения круглых уголков */ popup.groupDiv.style.overflow = 'visible'; popup.groupDiv.style.padding = '1px 0'; OpenLayers.Event.observe ( popup.div, 'click', OpenLayers.Function.bind ( function() { for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { this.layer.map.removePopup(this.layer.map.popups[i]); } }, this ) ); this.layer.map.addPopup(popup); } OpenLayers.Event.stop(evt); }, getMarkerIcon: function(url) { //TODO: перед присваиванием src нужно предварительно закешировать картинку, чтобы правильно определить размер var image = new Image(); image.src = url; /* kinda hack: We cannot determine icon size by its URL, before image is loaded, but we need to give something non-empty to Openlayers.Icon (as otherwise it will set w/h to 20px by default). So we give some crap, that will not be parsed by browser, and w/h will be set to 'auto' We cannot pass null instead of size, because Openlayers.Icon will set it to default size */ var width = "auto "; var height = "auto "; if (image.width) width = image.width; if (image.height) height = image.height; var size = new OpenLayers.Size(width, height); var calculateOffset = function(size) { return new OpenLayers.Pixel(-19, -61); // we don't know image size, how can we calculate it ? //return new OpenLayers.Pixel(-size.w/2, -size.h); }; return new OpenLayers.Icon(url, size, null, calculateOffset); }, CLASS_NAME: 'OpenLayers.Layer.GeoRSSAdv' }); //Грязный хак //OpenLayers.ImgPath = '/scripts/modules/openLayers/core/img/'; OpenLayers._getScriptLocation = function() { return '/scripts/modules/openLayers/core/'; } /** * общий управляющий класс */ openLayersMap = function() { this.map = null; this.busy = false; this.name = 'Map'; this.overlays = [];//заданные оверлеи this.loadedParts = {};//кэш загруженных оверлеев this.minSizeX = 500;//минимальный размер загружаемой области по X, px this.minSizeY = 500;//минимальный размер загружаемо области по Y, px this.precisionX = 1000;//точность по X, 1/deg this.precisionY = 1000;//точность по Y, 1/deg this.overlayPreloadX = 100;//размер области подкачки вне видимой области по X, px this.overlayPreloadY = 100;//размер области подкачки вне видимой области по Y, px this.show = function(nodeID) { var options = arguments.length > 1 ? arguments[1] : null; var extent = options && options.extent ? options.extent : [-180, -90, 180, 90]; var center = options && options.center ? options.center : [0, 0]; var minZoom = options && options.minZoom ? options.minZoom : 0; var maxZoom = options && options.maxZoom ? options.maxZoom : 12; var zoom = options && options.zoom ? options.zoom : minZoom; var controls = options && options.controls ? options.controls : null; var _this = this; this.map = new OpenLayers.Map ( nodeID, { minZoom: minZoom, maxZoom: maxZoom, controls: controls, projection: new OpenLayers.Projection('EPSG:900913'), displayProjection: new OpenLayers.Projection('EPSG:4326'), units: 'm', maxResolution: 156543.0339, maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34), isValidZoomLevel: function(zoomLevel) { return zoomLevel != null && zoomLevel >= this.minZoom && zoomLevel <= this.maxZoom; }, eventListeners: { 'moveend': function(e) { _this.onMoveEnd(e); }, 'zoomend': function(e) { _this.onZoomEnd(e); } } } ); this.map.restrictedExtent = this.fromLongLat(new OpenLayers.Bounds(extent[0], extent[1], extent[2], extent[3])); this.map.addControl(new OpenLayers.Control.Navigation({'zoomWheelEnabled': true})); //this.map.addControl(new OpenLayers.Control.MousePosition()); //this.map.addControl(new OpenLayers.Control.LayerSwitcher()); /*var baseLayer = new OpenLayers.Layer.TMS ( "OpenStreetMap", "http://tile.openstreetmap.org/", { type: 'png', getURL: this.getTMSTileURL, displayOutsideMaxExtent: true } );*/ var baseLayer = new OpenLayers.Layer.TMS ( this.name, '/openLayers/map/tms', { type: 'jpg', getURL: this.getTMSTileURL, displayOutsideMaxExtent: true } ); this.map.addLayer(baseLayer); this.map.baseLayer.numZoomLevels = 1 + this.maxZoom; if (center) this.map.setCenter(this.fromLongLat(new OpenLayers.LonLat(center[0], center[1])), zoom); else this.map.zoomToMaxExtent(); } this.addSegmentedOverlay = function(type, title) { var url = arguments.length > 2 ? arguments[2] : ''; var params = arguments.length > 3 ? arguments[3] : {}; var overlay = { type: type, title: title, url: url, params: params }; this.overlays.push(overlay); return overlay; } this.refresh = function() { this.clearOverlaysData(); this.buildOverlaysData(); } this.buildOverlaysData = function() { if (this.busy) { var _this = this; setTimeout ( function() { _this.buildOverlaysData(); }, 500 ); } var _this = this; var bounds = this.map.getExtent(); this.toLongLat(bounds); var mapSizePxX = this.map.getSize().w;//ширина карты, px var mapSizePxY = this.map.getSize().h;//высота карты, px var mapSizeDegX = bounds.getWidth();//ширина карты, deg var mapSizeDegY = bounds.getHeight();//высота карты, deg var xFactor = mapSizeDegX / mapSizePxX;// deg на px var yFactor = mapSizeDegY / mapSizePxY;// deg на px var xCount = Math.round((2 * this.overlayPreloadX + mapSizePxX) / this.map.getTileSize().w);//количество областей по X var yCount = Math.round((2 * this.overlayPreloadY + mapSizePxY) / this.map.getTileSize().h);//количество областей по Y var sizeX = Math.round(this.precisionX * xFactor * Math.max(this.minSizeX, Math.round(mapSizePxX / xCount))) / this.precisionX;//размер области по X, deg var sizeY = Math.round(this.precisionY * xFactor * Math.max(this.minSizeY, Math.round(mapSizePxY / yCount))) / this.precisionY;//размер области по Y, deg var left = Math.round(this.precisionX * (bounds.left - xFactor * this.overlayPreloadX)) / this.precisionX;//левый край загружаемой области, deg var right = Math.round(this.precisionX * (bounds.right + xFactor * this.overlayPreloadX)) / this.precisionX;//правый край загружаемой области, deg var bottom = Math.round(this.precisionY * (bounds.bottom - yFactor * this.overlayPreloadY)) / this.precisionY;//нижний край загружаемой области, deg var top = Math.round(this.precisionY * (bounds.top + yFactor * this.overlayPreloadY)) / this.precisionY;//верхний край загружаемой области, deg for (var x = left; x < right; x += sizeX) { for (var y = bottom; y < top; y += sizeY) { var key = x + '_' + y; if (!this.loadedParts[key]) { this.loadedParts[key] = true; var bounds = new OpenLayers.Bounds(); bounds.extend(new OpenLayers.LonLat(x, y)); bounds.extend(new OpenLayers.LonLat(x + sizeX, y + sizeY)); for (var i = 0; i < this.overlays.length; i++) { var overlay = this.overlays[i]; var title = overlay.title + ' (' + x + ',' + y + ')'; var url = overlay.url; if (url.indexOf('?') < 1) url += '?'; url += '&BBOX=' + bounds.toBBOX(); if (overlay.params) for (var i in overlay.params) url += '&' + i + '=' + overlay.params[i]; overlay.params.projection = this.map.displayProjection; var newOverlay = null; switch (overlay.type) { case 'GeoRSS': newOverlay = new OpenLayers.Layer.GeoRSS ( title, url, overlay.params ); break; case 'GeoRSSAdv': newOverlay = new OpenLayers.Layer.GeoRSSAdv ( title, url, overlay.params ); break; case 'Text': newOverlay = new OpenLayers.Layer.Text ( title, {location: url, params: overlay.params} ); break; } if (newOverlay) { this.map.addLayer(newOverlay); this.loadedParts[key] = newOverlay; } } } } } } this.clearOverlaysData = function() { this.busy = true; for (var i in this.loadedParts) { if (this.loadedParts[i].div) this.map.removeLayer(this.loadedParts[i], false); } this.loadedParts = {}; this.busy = false; } this.centerToObject = function(objectID, callback) { var _this = this; OpenLayers.Request.GET ({ 'url': '/openLayers/map/object/data/' + objectID, 'success': function(request) { eval('var data = ' + request.responseText); if (data && data.longitude) { var longLat = _this.fromLongLat(new OpenLayers.LonLat(data.longitude, data.latitude)); _this.map.setCenter(longLat); if (callback) callback(data, longLat); } } }) } this.saveObjectLocation = function(objectID, longLat, callback) { OpenLayers.Request.GET ({ 'url': '/openLayers/map/location/save/' + objectID, 'params': { longitude: longLat[0], latitude: longLat[1] }, 'success': function(request) { eval('var data = ' + request.responseText); var result = data && data.success; if (callback) callback(result, data); } }) } this.setDragableObject = function(longLat, dragCallback) { var long = longLat[0]; var lat = longLat[1]; var _this = this; if (!this.objectLayer) { this.objectLayer = new OpenLayers.Layer.Vector ( 'Object', { projection: this.map.displayProjection, styleMap: new OpenLayers.StyleMap ({ pointRadius: 15, externalGraphic: '/scripts/modules/openLayers/images/marker.png', cursor: 'pointer' }) } ); this.map.addLayer(this.objectLayer); this.map.addControl(new OpenLayers.Control.MousePosition()); this.dragControl = new OpenLayers.Control.DragFeature(this.objectLayer); this.dragControl.onComplete = function(feature, pixel) { var location = feature.geometry.getBounds().getCenterLonLat(); _this.toLongLat(location); if (dragCallback) dragCallback(location, feature); } this.map.addControl(this.dragControl); } //перемещаем маркер в зону видимости, если он за пределами карты var maxExt = this.map.getMaxExtent(); if (!maxExt.containsLonLat(this.fromLongLat(new OpenLayers.LonLat(long, lat)))) { var mapLongLat = this.map.getCenter().clone(); this.toLongLat(mapLongLat); long = mapLongLat.lon; lat = mapLongLat.lat; } var longLat = new OpenLayers.LonLat(long, lat); this.fromLongLat(longLat); this.map.setCenter(longLat); if (this.objectMarker) this.objectLayer.removeFeatures([this.objectMarker]); this.objectMarker = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(longLat.lon, longLat.lat)); this.objectLayer.addFeatures([this.objectMarker]); return this.objectMarker; } this.getDragableObject = function() { return this.objectMarker ? this.objectMarker : null; } this.getDragableObjectLongLat = function() { return this.objectMarker ? this.toLongLat(this.objectMarker.geometry.getBounds().getCenterLonLat()) : null; } this.enableDragableObject = function() { this.dragControl.activate(); //перемещаем маркер в зону видимости, если он за ее пределами var mapExt = this.map.getExtent(); if (!mapExt.containsLonLat(new OpenLayers.LonLat(this.objectMarker.geometry.x, this.objectMarker.geometry.y))) { var mapCenter = mapExt.getCenterLonLat(); if (this.objectMarker) this.objectLayer.removeFeatures([this.objectMarker]); this.objectMarker = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(mapCenter.lon, mapCenter.lat)); this.objectLayer.addFeatures([this.objectMarker]); } } this.disableDragableObject = function() { this.dragControl.deactivate(); } this.getTMSTileURL = function(bounds) { var res = this.map.getResolution(); var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w)); var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h)); var z = this.map.getZoom(); var limit = Math.pow(2, z); x = ((x % limit) + limit) % limit; return this.url + '?zoom=' + z + '&x=' + x + '&y=' + y + '&type=' + this.type; } this.toLongLat = function(object) { return object.transform(this.map.projection, this.map.displayProjection); } this.fromLongLat = function(object) { return object.transform(this.map.displayProjection, this.map.projection); } this.onMoveEnd = function(event) { this.buildOverlaysData(); } this.onZoomEnd = function(event) { this.clearOverlaysData(); } }