vector layer loading issue in openlayers 3 - openlayers-3

I have an issue regarding vector loading in ol3.
I am using a geoserver which doesn't handle js callback
In order to have my features loaded, I have to add them in the loader's ajax done function :
var buildLoader = function(vectorSource, $vector) {
return function(extent, resolution, projection) {
extent = ol.extent.applyTransform(extent, ol.proj.getTransform("EPSG:3857", "EPSG:4326"));
var url = 'https://myurl/' + $vector.attr("url") +
'?service=WFS' +
'&version=' + $vector.attr("version") +
'&request=GetFeature' +
'&typename=' + $vector.attr("typename") +
'&srs=' + $vector.attr("projection") +
'&bbox=' + extent +
'&outputFormat=json';
$.ajax({
url: url,
dataType: 'json',
xhrFields: {
withCredentials: true
}
})
.done(function(response) {
vectorSource.addFeatures(vectorSource.readFeatures(response));
});
}
}
I then build an array of vectors to be added on my map.
for (index=0; index < vectors.length; index++) {
var $vector = $(vectors[index]);
var vectorSource = new ol.source.ServerVector({
format: new ol.format.GeoJSON(),
loader: buildLoader(vectorSource, $vector),
projection: 'EPSG:3857'
});
// ... //
datas[index] = new ol.layer.Vector({
source: vectorSource,
visible: 'false',
style: iconStyle
});
}
The problem here is that the vectorSource used by the loader is always [index - 1]
I have found an Hack, by defining the loader function after the instantiation:
var vectorSource = new ol.source.ServerVector({
format: new ol.format.GeoJSON(),
projection: 'EPSG:3857'
});
vectorSource.loader_ = buildLoader(vectorSource, $vector);
I find this ugly enough, but there is no setLoader() available for the ServerVector type. Do you know if there is anoter solution which does not involve using another geoserver?

I save a reference to the VectorSource object instance in the buildLoader function (instead of argument).
vectorSource = this;
Then I use that reference in the done() function:
vectorSource.addFeatures(vectorSource.readFeatures(response));
Full source:
var buildLoader = function($vector) {
return function(extent, resolution, projection) {
vectorSource = this;
extent = ol.extent.applyTransform(extent, ol.proj.getTransform("EPSG:3857", "EPSG:4326"));
var url = 'https://myurl/' + $vector.attr("url") +
'?service=WFS' +
'&version=' + $vector.attr("version") +
'&request=GetFeature' +
'&typename=' + $vector.attr("typename") +
'&srs=' + $vector.attr("projection") +
'&bbox=' + extent +
'&outputFormat=json';
$.ajax({
url: url,
dataType: 'json',
xhrFields: {
withCredentials: true
}
})
.done(function(response) {
vectorSource.addFeatures(vectorSource.readFeatures(response));
});
}
}

Related

Get term for selected autocomplete when multiple are on one page

I have a page where I am adding jquery-ui autocompletes dynamically
My .autocomplete() code includes a $.getJSON('my_url', my_payload) where, in my_payload,' I am trying to send the request.term (what I typed into the jqueryui textbox) as well as the id of the jquery ui text box.
The problem is, for all the dynamically added textboxes, they were just picking up the term and id of the original autocomplete.
I managed to find a way to get the id of the added (not original) autocomplete by wrapping the autocomplete in a function that has the added field passed in as a parameter, but because the 'term' is in the request, which comes from .autocomplete, I do not know how to get this for the new ones.
https://jsfiddle.net/amchugh89/1L8jvea5/4/
//=======dynamic formset script from https://medium.com/all-about-
django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0======
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
if ($(this).attr('name')){
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
if($(this).attr('id').includes('gl')){
console.log($(this).attr('id'))
make_autocomplete($(this))
}
}
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
//====================
//AUTOCOMPLETE==(that allows for multiple ACs
https://stackoverflow.com/questions/24656589/using-jquery-ui-autocomplete-
with-multiple-input-fields)===================================
function make_autocomplete(ee) {
ee.on("focus", function(){ //.autocomplete({
$(this).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
//with the formset, I want to get the row for which I am typing in the
'term'
var this_formset_row_autocomplete_id
=ee.attr('id');//$(this.element).prop("id");//
$(this).attr('id');
console.log(this_formset_row_autocomplete_id);
var corresponding_branch_html_id =
this_formset_row_autocomplete_id.replace('gl_account','branch');
var this_formset_row_branch_sym_id =
$('#'+corresponding_branch_html_id).val();
//console.log(corresponding_branch_html_id, this_formset_row_branch_sym_id)
var appended_data={term:term,
this_formset_row_branch_sym_id:this_formset_row_branch_sym_id};
console.log(appended_data);
$.getJSON( "{% url 'dashapp:account_autocomplete' %}", appended_data,
function( data,
status, xhr ) {
//cache[ term ] = data;
response( data );
});
}
});
});
}//end function make_autocomplete
var ee =$( ".account_autocomplete" )
make_autocomplete(ee)
//===============
You may want to try to make it more simple for testing. Something like:
function make_autocomplete(obj) {
obj.autocomplete({
minLength: 2,
source: function(req, resp) {
var myData = {
term: req.term,
original_form_branch_id: $(this).closest("form").attr("id"),
this_formset_row_branch_sym_id: $(this).closest(".row").find("select").val()
}
$.getJSON("myurl", myData, function(results) {
resp(results);
});
}
});
}
Fiddle: https://jsfiddle.net/Twisty/pywb9nhv/23/
This uses .closest() to gather details from the relative objects. Also I do not see any benefit to initializing Autocomplete on focus event.
If you would like further help, please provide Example Data that can be used in a working example.
Hope that helps a little.

How can I create prototype objects inside Zapier?

I am working on our Application-integration inside Zapier and using zapier's built in methods for polling data. The script is now long and use a lot of repetitive function objects. How can I use prototype inheritance model for each attribute call so that I can reuse it for similar calls for other attributes? A typical api call is as follows:
var Zap = {
myattribute_post_poll: function(bundle) {
var results = JSON.parse(bundle.response.content);
results.value.reverse();
//attribute call
var cRequest = {
'url': "myURL.com/a/" + bundle.auth_fields.tenant_id +
"/odata/standard.odata/Catalog_attibute(guid'" + results.value[i].attribute_Key + "')?$format=json",
'headers': {
"Authorization": "Basic " + btoa(bundle.auth_fields.username + ':' + bundle.auth_fields.password)
},
'method': "GET"
};
var cResponse = z.request(cRequest);
try{
var JSONResponse = JSON.parse(cResponse.content);
results.value[i].Customer_name = JSONResponse.Description;
} catch(error){
console.log(error);
results.value[i].Customer_name = results.value[i].Company_Key;
}
return results;
}
The best technique is just to break into reusable properties on Zap:
var Zap = {
reusable_thing: function(arg) {
return arg + 1;
},
attr_pre_poll: function(bundle) {
bundle.request.params = Zap.reusable_thing(1);
return bundle.request;
}
};
This might be helpful to others, so adding my prototype object here:
var Zap = {
attrGuidRequest : function(obj, document, key){
var attrResponse = JSON.parse(
z.request({
'url': "myUrl" + tenant_id +
"/odata/.." + document + "(guid'" + key + "')?$format=json",
'headers': {
"Authorization": "Basic " + btoa(username + ':' + password)
},
'method': "GET"
}).content) || {};
return attrResponse;
}
}

OpenLayers WFS request on mouseclick to GeoServer doesn't load features into vector layer

I would appreciate advice on getting an OpenLayers WFS request to GeoServer working in OL3.2 or later, triggered by a mouse singleclick.
By way of background, I have had this working fine for a year at http://maps.nls.uk/geo/find/ using OL 3.1. However, Firefox version 43.0 records the mouse click event at the top left corner of the map canvas, not on the real pixel location clicked on - earlier versions of Firefox, Chrome and IE record the correct pixel location on the canvas. From my basic tests, later versions of OL after 3.1 record the correct pixel location using Firefox 43.0, so I would like to upgrade to a newer version of OL.
My original code in OL3.1 is as follows:
var urlgeoserver = 'http://geoserver2.nls.uk/geoserver/wfs?service=WFS' +
'&version=1.1.0&request=GetFeature&typename=' + TypeName +
'&outputFormat=text/javascript&format_options=callback:loadFeatures' +
'&srsname=EPSG:3857&cql_filter=INTERSECTS(the_geom,POINT('
+ point27700[0] + ' ' + point27700[1] + '))';
}
var vectorSource = new ol.source.ServerVector({
format: new ol.format.GeoJSON(),
loader: function(extent, resolution, projection) {
var url = urlgeoserver
$.ajax({
url: url,
dataType: 'jsonp',
jsonpCallback: 'loadFeatures',
success: handleJson
});
},
strategy: ol.loadingstrategy.createTile(new ol.tilegrid.XYZ({
maxZoom: 19
})),
projection: 'EPSG:3857'
});
function handleJson(data) {
vectorSource.addFeatures(vectorSource.readFeatures(data));
....
I have tried adapting this following the example at http://openlayers.org/en/v3.6.0/examples/vector-wfs.html and OL 3.6 with the code below:
var urlgeoserver = 'http://geoserver2.nls.uk/geoserver/wfs?service=WFS' +
'&version=1.1.0&request=GetFeature&typename=' + TypeName +
'&outputFormat=text/javascript&format_options=callback:loadFeatures' +
'&srsname=EPSG:3857&cql_filter=INTERSECTS(the_geom,POINT('
+ point27700[0] + ' ' + point27700[1] + '))';
}
vectorSource = new ol.source.Vector({
loader: function(extent, resolution, projection) {
var url = urlgeoserver
// use jsonp: false to prevent jQuery from adding the "callback"
// parameter to the URL
$.ajax({url: url, dataType: 'jsonp'});
},
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
maxZoom: 19
}))
});
window.loadFeatures(response) {
vectorSource.addFeatures(geojsonFormat.readFeatures(response));
};
However I try things, it fails to retrieve features from GeoServer into vectorSource and I would appreciate any pointers or suggestions.
Many thanks,
Just in case helpful for others, following further investigation, I realised I just needed to add a 'jsonp: false' to the $.ajax query for it to work. The correct vectorSource syntax is therefore:
var geojsonFormat = new ol.format.GeoJSON();
var vectorSource = new ol.source.Vector({
loader: function(extent, resolution, projection) {
var url = urlgeoserver
$.ajax({url: url, dataType: 'jsonp', jsonp: false})
},
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
maxZoom: 19
}))
});
window.loadFeatures = function(response) {
vectorSource.addFeatures(geojsonFormat.readFeatures(response));
};
This is implemented at: http://maps.nls.uk/geo/find/

Trying to eliminate closure error in google map eventListener

I have a google map with a load of markers on it, each corresponding to a different post in the html. Each marker id is the same as each post id. Inside the map initialize = function() {... I have the following code (I'm using gon to pass info from rails to javascript):
for (m = 0; m < gon.markers.length; m++) {
marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(gon.markers[m].lat, gon.markers[m].lng),
icon: image,
infowindow: gon.markers[m].infowindow,
id: gon.markers[m].id
});
google.maps.event.addListener(marker, 'mouseover', function() {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
// console.log("marker.id: " + marker.id);
// console.log("this.id" + this.id);
$('#' + marker.id).css('background', 'red');
});
google.maps.event.addListener(marker, 'mouseout', function() {
var image = $("#map-canvas").data('marker1');
this.setIcon(image);
$('#' + marker.id).css('background', 'white');
});
markers[markers.length] = marker;
}
Uncommenting the console.log lines demonstrates that it is the classic closure problem (marker.id always has the same value no matter which marker is hovered on).
My question is, how do I code it properly so it does as intended? I just can't get the code right now matter what I try. I've tried stuff like this but is just doesn't work:
marker.on('mouseover', noticeHover(marker.id));
function noticeHover(id) {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
$('#' + id).css('background', 'gainsboro');
}
Wrap the entire code that handles the marker-creation into a function and pass the items inside the loop as argument to this function:
for (m = 0; m < gon.markers.length; m++) {
//anonymous,self-executing function
(function(props){
var goo = google.maps,
marker = new goo.Marker({
map: map,
position: new goo.LatLng(props.lat,
props.lng),
icon: image,
infowindow: props.infowindow,
id: props.id
});
goo.event.addListener(marker, 'mouseover', function() {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
$('#' + marker.id).css('background', 'red');
});
goo.event.addListener(marker, 'mouseout', function() {
var image = $("#map-canvas").data('marker1');
this.setIcon(image);
$('#' + marker.id).css('background', 'white');
});
markers.push(marker);
}(
gon.markers[m]//pass current loop-item as argument
));
}

NetworkError: 403 Forbidden - http://www.googleapis.com/fusiontables/v1/query? google fusion tables

I am wondering what is wrong in my code to be producing the following error message:
NetworkError: 403 Forbidden - http://www.googleapis.com/fusiontables/v1/query?
I believe that I am properly referencing the new SQL V1 API and the tables I am referencing are base tables that allow data to be exported.
Code Snippet
function getEcoliData(beachID) {
//local namespace
var rows = [];
var items = [];
var queryURL = "http://www.googleapis.com/fusiontables/v1/query?sql=";
var queryTail = '&jsonCallback=?';
var whereClause = "WHERE 'Beach_ID' = " + beachID;
var query = "SELECT 'Sample_Date', 'Average_E.coli_Density','Recreational_Water_Quality_Guideline' FROM 1-ZORhnuDELDxO1FsmzJ60K3JzWOYOKvsHibrQeo " + whereClause + " ORDER BY 'Sample_Date' DESC";
var queryText = encodeURI(query);
infoWindow = new google.maps.InfoWindow();
$.ajax({
type: "GET",
url: queryURL + queryText + queryTail,
cache: false,
dataType: 'jsonp',
jsonCallback: 'jsonCallback',
success: function (data) {
rows = data.tables.rows;
for (var i = 0; i < rows.length; i++) {
items.push(rows[i]);
}
return items;
},
error: function () {
alert("Data is not available for this location at the present time, please check back at a later time. Thank you.");
}
});
}
any suggestions are welcomed. Thanks in advance.
Michael
use https:// instead of http:// . You also need to send a valid key via the URL(be sure that you've activated the Fusion-Tables-API-service inside the API-console before you use the key).

Resources