I have trouble about selecting the feature layer based on its attribute. I got this code below but it says:
Uncaught TypeError: Cannot read property 'features' of undefined
here's my code:
var init = function () { // A function that will initialize and execute all the declared variables
var geographic = new OpenLayers.Projection("EPSG:4326"); // Setting the standard geographic projection
var mercator = new OpenLayers.Projection("EPSG:3857"); // Setting the universal geographic projection
map = new OpenLayers.Map('map'); // Creating & initializing map constructor
var base_osm = new OpenLayers.Layer.OSM("OpenStreetMap"); // Setting OpenStreetMap as a BaseMap
map.addControl(
new OpenLayers.Control.MousePosition({
prefix: '<small style="color:blue">',
suffix: '</small>',
numDigits: 2,
emptyString: '<small style="color:red">' + 'Mouse is not over map.' +'</small>'
})
);
var layer_agao = new OpenLayers.Layer.Vector("Agao");
map.addLayers([layer_agao, base_osm]); // Adding the vector layer to the map
map.addControl(new OpenLayers.Control.LayerSwitcher());
selectControl = new OpenLayers.Control.SelectFeature(layer_agao, {
onSelect: onFeatureSelect, onUnselect: onFeatureUnselect
});
map.addControl(selectControl);
selectControl.activate();
map.setCenter(new OpenLayers.LonLat(13975400.3513, 999830.692078),16);
var format_agao = new OpenLayers.Format.GeoJSON(); //initializing and calling the rendered GeoJSON Layer from views.py
var feat_agao = format_agao.read({{agao_transform|safe}});
layer_agao.addFeatures(feat_agao);
layer_agao.events.on({
featureselected: function(event) {
var feature = event.feature;
var area = feature.geometry.getArea();
var id = feature.attributes.newpin;
var output = "Land Pin: " + id + "<br/>" + "Area: " + area.toFixed(12);
document.getElementById("status").innerHTML = output;
}
});
init.showparcel();
}
init.showparcel = function (getpin){
for(var f=0;f<layer_agao.features.length;f++) {
if(layer_agao.features[f].attributes.newpin == getpin) {
selectControl.select(layer_agao.features[f]);
break;
}
}
}
I also read about getfeaturesbyattribute, but i can't find any example. So, is there other way to call the specific feature layer on click (event)? This is for my searching...
You would need to use the getFeaturesByAttribute or track features in your own index with their FID as the index of that object, and then use getFeatureByFid.
I usually prefer to track them in my own object or hashtable and then reference by FID.
In your example I would pull in an unique id on the attribs that you can search yourself outside of openlayers, and then use the getFeaturesByAttribute to reference the unique id that you know exist. If that doesn't may sense hit me up in the comments.
vlayer.getFeaturesByAttribute("fid", target)[0]
http://dev.openlayers.org/docs/files/OpenLayers/Layer/Vector-js.html#OpenLayers.Layer.Vector.getFeaturesByAttribute
The correct way to add a listener to a Vector.Layer is layer.events.register(type, obj, listener) as shown in the comments in the source: http://trac.osgeo.org/openlayers/browser/trunk/openlayers/lib/OpenLayers/Layer/Vector.js. Note, the listener for featureselected is passed the selected feature, not the event as you have it.
So, in your case:
layer_agao.events.on('featureselected', null, function(feature){
//do something with the feature
var area = feature.geometry.getArea();
var id = feature.attributes.newpin;
var output = "Land Pin: " + id + "<br/>" + "Area: " + area.toFixed(12);
document.getElementById("status").innerHTML = output;
});
getFeaturesByAttribute doesn't look like it is what you need, based on your code sample, though it is useful in specific cases.
Related
I have a function prototype that loads data from a path. The trick is that I need to change the path afterward. I tried call, apply, bind and even assign but as I am a novice I did not find the solution.
Here a sample of my code :
Chat.prototype.loadMessages = function() {
this.messagesRef = this.database;
var setMessage = function(data) {
var val = data.val();
this.displayMessage(data.key, val.name, val.text);
}.bind(this);
};
var chat = new Chat
function setPath (newpath) {
chat.loadMessages.messageRef = newpath; // I guess, it is where I'm wrong...
chat.loadMessages(); // It should load messages from the new path in my chat container.
}
As I said I also tried :
chat.loadMessages.call(newpath);
or
var setPath = function(newpath) {
chat.loadMessages(newpath);
}.bind(chat);
setPath();
chat.loadMessages();
But the chat container continues to disclose messages from the old path...
This looks a bit convoluted. Just pass messagesRef as a parameter and make it default to this.database:
Chat.prototype.loadMessages = function(messagesRef = this.database) {
// do whatever is needed with messagesRef
};
chat = new Chat();
chat.loadMessages(); // load from the default location
chat.loadMessages('foobar'); // load from this specific location
It looks like you are creating a function with loadMessages, which is fine but you need to pass in a value to set the new path. Is this more of what you were thinking?
Chat.prototype.loadMessages = function (newPath) {
this.messagesRef = newPath || this.database; // if newPath is empty than default to this.database
var setMessage = function(data) {
var val = data.val();
this.displayMessage(data.key, val.name, val.text);
};
var chat = new Chat
function setPath (newpath) {
chat.loadMessages(newpath);
}
I have developed a 3D viewer of buildings. What I'm trying to add now is the selection of the content of a WMS (Web Map Service) below the building entities.
Basically, I want to be able to select the building at the position were the user left clicks. The colour of the building should change (which works). And I want to retrieve the information of the Web Map Service at the position were the user clicked.
This is what I have coded so far:
var pickColor = Cesium.Color.CYAN.withAlpha(0.7);
var selectedEntity = new Map();
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(click) {
var pickedObject = viewer.scene.pick(click.position);
if (Cesium.defined(pickedObject)) {
var entityId = pickedObject.id._id;
var oldColor = buildingMap.get(entityId).polygon.material.color;
buildingMap.get(entityId).polygon.material.color = pickColor;
selectedEntity.set(entityId, oldColor);
var currentLayer = viewer.scene.imageryLayers.get(1);
if (typeof currentLayer !== 'undefined') {
var info = currentLayer._imageryProvider._tileProvider.getTileCredits(click.position.x, click.position.y, 0);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
However, my variable "info" stays undefined, whereas I expect it to return an array.
For WMS you need to use the wms GetFeatureInfo capability:
var pickRay = viewer.camera.getPickRay(windowPosition);
var featuresPromise = viewer.imageryLayers.pickImageryLayerFeatures(pickRay, viewer.scene);
if (!Cesium.defined(featuresPromise)) {
console.log('No features picked.');
} else {
Cesium.when(featuresPromise, function(features) {
// This function is called asynchronously when the list if picked features is available.
console.log('Number of features: ' + features.length);
if (features.length > 0) {
console.log('First feature name: ' + features[0].name);
}
});
}
I am new to JavaScript and I have beginners grip on the concepts I have a function that gets the label from a kml and displays it on screen (some of the clustering part of this function was supplied by someone on S/O). it works perfectly for all the kmls that are loaded except the First one.
I am sure that the problem is something to do with a variable and its scope, but for the life of me i cannot see where or how I am getting an error, I correction to the code would be a great help, but correction to my understanding (or lack there of) just as helpful.
many thanks in adavance
here is the code
EDIT
1) I have changes the function getlabel a number of times and the changes are only seen on kmls loaded outside of the first ajax call shown below. I don’t for the life of em understand why this is happening. It may be a context issue, however this is beyond my understanding of the topic
var tripid=1;
var myStyles;
var cfarmerid;
var navigate=true;
var edit=false;
var vectors;
var polyControl;
var bound=false;
var mycluster;
var label=" ";
$(document).ready(function(){
$.ajax({
type: "POST",url: "temp.php",dataType: "json",
error: function(e){
alert('Error: '+e);
},
success: function (data) {
if(data[0]==="not"){
window.location = "http://www.g4ema.com/index.html";
}
maxlat=data[0];
maxlon=data[1];
minlat=data[2];
minlon=data[3];
tripid=parseInt(data[4]);
var bbox=new OpenLayers.Bounds();
bbox.extend(new OpenLayers.LonLat(minlon,minlat));
bbox.extend(new OpenLayers.LonLat(maxlat,maxlon));
bbox.toBBOX();
map = new OpenLayers.Map("map");
//var layer= new OpenLayers.Layer.OSM();
mycluster = new OpenLayers.Strategy.Cluster(
{
threshold: 2, // single clusters are shown as features
shouldCluster: function(cluster, feature)
{
if (feature.geometry.CLASS_NAME === "OpenLayers.Geometry.Point" &&
cluster.cluster[0].geometry.CLASS_NAME === "OpenLayers.Geometry.Point") {
return OpenLayers.Strategy.Cluster.prototype.shouldCluster.apply(this, arguments);
} else {
return false;
}
}
});
var layer = new OpenLayers.Layer.Google(
"Google Hybrid",
{type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20});
layer.wrapDateLine=false;
map.addLayer(layer);
myStyles = new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
strokeColor: "#00ffff",
strokeWidth:5,
strokeOpacity:1,
fillColor:"#003399",
fillOpacity: 1,
labelYOffset: 15,
pointRadius: 4,
label:"${getLabel}",
fontColor:"#ff0000"
}, {
context: {
getLabel: function (f) {
label=" ";
if (f.cluster) { // is a cluster
if (f.cluster[0].attributes.label!==" ") {
label= " " + f.attributes.count + " " +
f.cluster[0].attributes.label;
} else {
label= " " ;//+ f.attributes.count + "init";
}
} else { // is not cluster
if (f.attributes.label!==" ") {
label= " " + f.attributes.label;
}else{
label=" ";
}
}
if(!label){label=" ";}
return label;
}
}
})
});
kmlLayer = new OpenLayers.Layer.Vector("Trip", {
styleMap: myStyles,
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.Fixed(),mycluster],
protocol: new OpenLayers.Protocol.HTTP({
params:{ tripid:tripid},
url: "kml2.php",
readWithPOST:true,
//{userid:userid,tripid:tripid},
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
})
})
});
map.addLayer(kmlLayer);
var clat=(parseFloat(minlat)+parseFloat(maxlat))/2;
var clon=(parseFloat(minlon)+parseFloat(maxlon))/2;
var lonlat = new OpenLayers.LonLat(clon,clat).transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:900913"));
map.setCenter(lonlat);
map.zoomTo(15);
First of all, I don't see the advantage of declaring the label variable with global scope in the context of the code you've shared. Since you're returning a label from the getLabel function then I think you should just declare var label; at the top of the getLabel function and return the value of that local variable from the function.
Second, the only way I can see that "undefined" would be returned from getLabel is if f.attributes.label is undefined. I would try a code block such as:
} else { // is not cluster
if (f.attributes.label != null && typeof(f.attributes.label != "undefined") {
// if (f.attributes.label) { // alternate simpler if statement
label= " " + f.attributes.label;
} else {
label = " ";
}
}
For anyone looking this with the same problem,
The above code is faultless, the reason this wasn't working is I was calling another function later in the $document.ready() and this was refining the mycluster variable. I am very sorry for those you have looked at this and couldn't see the problem.
but the above code will work FINE
I am attemtping to call a dojo tab container within an ESRI pop-up. The code that I have (see below) is able to create a pop-up with a tab container and the contents, but also creates three 'dead' dropdown menus. Is there a way to create the pop-up without the dropdown menus?
var map;
var resizeTimer;
var identifyTask,identifyParams;
function init() {
//setup the popup window
var popup = new esri.dijit.Popup({
fillSymbol: new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255,0,0]), 2), new dojo.Color([255,255,0,0.25]))
}, dojo.create("div"));
map = new esri.Map("map",{
infoWindow:popup,
});
dojo.connect(map,"onLoad",mapReady);
//Add the imagery layer to the map. View the ArcGIS Online site for services
//http://arcgisonline/home/search.html?t=content&f=typekeywords:service
var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
map.addLayer(basemap);
var landBaseLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://<someServer>/ArcGIS/rest/services/test/MapServer");
map.addLayer(landBaseLayer)
}
function mapReady(map) {
dojo.connect(map,"onClick",executeIdentifyTask);
//create identify tasks and setup parameters
identifyTask = new esri.tasks.IdentifyTask("http://<someServer>/ArcGIS/rest/services/test/MapServer");
identifyParams = new esri.tasks.IdentifyParameters();
identifyParams.tolerance = 3;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [0];
identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = map.width;
identifyParams.height = map.height;
//resize the map when the browser resizes
dojo.connect(dijit.byId('map'), 'resize', map,map.resize);
}
function executeIdentifyTask(evt) {
identifyParams.geometry = evt.mapPoint;
identifyParams.mapExtent = map.extent;
var deferred = identifyTask.execute(identifyParams);
deferred.addCallback(function(response) {
// response is an array of identify result objects
// Let's return an array of features.
return dojo.map(response, function(result) {
var feature = result.feature;
feature.attributes.layerName = result.layerName;
console.log(feature.attributes.OBJECTID);
var template = new esri.InfoTemplate();
template.setTitle("</b>Hello World</b>");
template.setContent(getWindowContent);
feature.setInfoTemplate(template);
return feature;
});
});
// InfoWindow expects an array of features from each deferred
// object that you pass. If the response from the task execution
// above is not an array of features, then you need to add a callback
// like the one above to post-process the response and return an
// array of features.
map.infoWindow.setFeatures([ deferred ]);
map.infoWindow.show(evt.mapPoint);
}
function getWindowContent(graphic) {
//make a tab container
var tc = new dijit.layout.TabContainer({ });
return tc.domNode;
}
dojo.addOnLoad(init);
It appears changing the TabContainer code to the following will fix the issue:
var tc = new dijit.layout.TabContainer({
style: "width:100%;height:100%;",
useMenu: false,
useSlider: false,
}, dojo.create('div'));
I am trying to use the titanium reverseGeocoder but I am having a strange issue which I think is a "scope" issue. I can't quite understand why the last log call I make returns null values when I have defined the variables in that scope.
var win = Titanium.UI.currentWindow;
Ti.include('includes/db.js');
var city = null;
var country = null;
Titanium.Geolocation.reverseGeocoder( Titanium.UI.currentWindow.latitude,
Titanium.UI.currentWindow.longitude,
function(evt) {
var places = evt.places;
if (places && places.length) {
city = places[0].city;
country = places[0].country;
}
Ti.API.log(city + ', ' + country); // <<< RETURNS CORRECT VALUES
});
Ti.API.log(city + ', ' + country); // <<< RETURNS NULL VALUES
This is an async call as Davin explained. You will have to call a function within the reverse geocode function.
A suggestion I can give you is to work event-based. Create events, and fire events. An example:
Titanium.UI.currentWindow.addEventListener('gotPlace',function(e){
Ti.API.log(e.city); // shows city correctly
});
Titanium.Geolocation.reverseGeocoder( Titanium.UI.currentWindow.latitude,
Titanium.UI.currentWindow.longitude,
function(evt) {
var city, country, places = evt.places;
if (places && places.length) {
city = places[0].city;
country = places[0].country;
}
Ti.API.log(city + ', ' + country); // <<< RETURNS CORRECT VALUES
Titanium.UI.currentWindow.fireEvent('gotPlace',{'city': city, 'country': country});
});