Leaflet layer visualization problems with ajax Error: parseResponse was not called - ajax

I'm creating a Leaflet viewer where I use ajax to get a geoserver OWS to be able to customize the display style with the following function:
function GetGeoserverJson(layer,geoserverURL,geoserverLayerName,layerAtributes,layerStyle) {
defaultParameters = {
service: 'WFS',
version: '1.0.0',
request: 'GetFeature',
maxFeatures: 120000,
outputFormat: 'text/javascript'
};
parameters = L.Util.extend(defaultParameters,geoserverLayerName);
console.log(parameters)
$.ajax({
url: geoserverURL + L.Util.getParamString(parameters),
dataType: 'jsonp',
jsonpCallback: 'parseResponse',
success: function (data) {
geoJsonLayer= new L.GeoJSON(data,{pointToLayer: function (geoJsonPoint, latlng) {return
L.circleMarker(latlng);}, onEachFeature: layerAtributes, style:layerStyle})
layerName.addLayer(geoJsonLayer);
}
});
}
Layers code:
geoserverURL= 'http://urladdress/geoserver/workspace/ows'
function PresenceAttributes(feature, layer) {
// layer.bindPopup("<b>Zone:</b> <br>"+feature.properties.zone+"<br><b>Taxon:</b><br>"+feature.properties.taxon+"<br><b>Species:</b> <br><i>"+feature.properties.species+"</i>");
layer.bindPopup(
"<table class='featureInfo'><caption class='featureInfo'>Presence</caption><tbody><tr><th>source</th><th>latitude</th><th>longitude</th></tr><tr><td>"
+feature.properties.source+"</td><td>"+feature.properties.latitude+"</td><td>"+feature.properties.longitude+"</td></tr></tbody></table>"
);
}
var NISStyle= function(feature) {
// console.log(feature)
var taxon_nis=feature.properties.taxon_class;
switch (taxon_nis) {
case "Bivalvia": {return {color:"#d19211"};}
case "Gastropoda": {return {color:"#8a6fce"};}
case "Polyplacophora": {return {color:"#2fbb00"};}
}
}
var NISAttributes= function(feature, layer) {
// layer.bindPopup("<b>Zone:</b> <br>"+feature.properties.zone+"<br><b>Taxon:</b><br>"+feature.properties.taxon+"<br><b>Species:</b> <br><i>"+feature.properties.species+"</i>");
layer.bindPopup(
"<table class='featureInfo'><caption class='featureInfo'>NIS historical</caption><tbody><tr><th>latitude</th><th>longitude</th><th>country</th></th><th>Site Name</th></th><th>Class</th><th>Species</th><th>Year first record</th><th>Reference</th></tr><tr><td>"
+feature.properties.latitude+"</td><td>"+feature.properties.longitude+"</td><td>"+feature.properties.country+"</td><td>"+feature.properties.site_name+"</td><td>"+feature.properties.taxon_class+"</td><td>"+feature.properties.species+"</td><td>"+feature.properties.year_first+"</td><td>"+feature.properties.reference+"</td></tr></tbody></table>"
);
}
var ParasitesAttributes= function (feature, layer) {
// layer.bindPopup("<b>Zone:</b> <br>"+feature.properties.zone+"<br><b>Taxon:</b><br>"+feature.properties.taxon+"<br><b>Species:</b> <br><i>"+feature.properties.species+"</i>");
layer.bindPopup(
"<table class='featureInfo'><caption class='featureInfo'>Parasites</caption><tbody><tr><th>Country</th><th>Zone</th><th>Latitude</th><th>Longitude</th><th>Taxon</th><th>Species</th></tr><tr><td>"
+feature.properties.country+"</td><td>"+feature.properties.zone+"</td><td>"+feature.properties.latitude+"</td><td>"+feature.properties.longitude+"</td><td>"+feature.properties.taxon
+"</td><td>"+feature.properties.species+"</td></tr></tbody></table>"
);
}
var ParasytesStyle= function (feature){
var taxon_parasites=feature.properties.taxon_id;
switch (taxon_parasites) {
case 1: {return {color:"#4c6fb6"};} // Artropoda-
case 2: {return {color:"#fcbf7d"};} //Alveolata-
case 3: {return {color:"#3cbfbf"};} //Platelminthes-
case 4: {return {color:"#b9d989"};} //Rhizaria-
case 5: {return {color:"#ff7f00"};} //Amoebozoa
case 6: {return {color:"#de524b"};} //Bacteria-
case 7: {return {color:"#aebaca"};} // Others-
case 8: {return {color:"#f47a6a"};} //Fungi-
case 9: {return {color:"#999999"};} //ND-
// case 10: {return {color:"grey"}};
// case 11: {return {color:"white"}};
}
}
var GeoservePresence={typeName:'COCKLES:aa_cockles_presence'};
var GeoserveNIS={typeName:'COCKLES:aa_nis_historical'};
var GeoserveParasites={typeName:'COCKLES:aa_cockles_pathogens'}
var CocklesPresence= new L.markerClusterGroup();
var CocklesNISAA= new L.markerClusterGroup();
var CocklesParasites= new L.markerClusterGroup();
GetGeoserverJson(CocklesPresence,CetmarGeoserver,GeoservePresence,PresenceAttributes,{color:"#FFC000"});
GetGeoserverJson(CocklesNISAA,CetmarGeoserver,GeoserveNIS,NISAttributes,NISStyle);
GetGeoserverJson(CocklesParasites,CetmarGeoserver,GeoserveParasites,ParasitesAttributes,ParasytesStyle);
When I code only one layer it works perfectly, but if I run the function with more layers, layers represent data incorrectly (data of NIS layer are represented in parasites one, etc.) I don't really know much about ajax and I'm new to javascript and Leaflet, so I hardly can figure out what I'm doing wrong. Maybe some problem with asynchronism? Can anybody help me?

Related

Leaflet mapping: Assign object to fetch promise for local GeoJSON file

I am looking to assign as an object a Fetch API promise from a local GeoJSON file.
Here is the code
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites
}).addTo(map);
});
};
I tried the call back method, as advised here
Saving fetched JSON into variable
(EDIT) New code, but there is still a missing formal parameter
function getData("data/sites.geojson", cb) {
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function (feature, layer) {
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
.then(function(result) {
cb(result);
});
});
};
getData("data/sites.geojson", function (data) {
return console.log({data});
});
Most probably just incorrect syntax of your callback function:
// Use either arrow function
getData("data/sites.geojson", (data) => {
return console.log({data});
});
// or standard function
getData("data/sites.geojson", function (data) {
return console.log({data});
});
I found the way to work this out by adding within the fetch function, what I originally wanted to do on the map.
This was to add a L.controlLayer using the geojson as overlay.
This is the code that made it work:
let sites = getData()
.then((function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function LayerControl(feature, layer) {
var popupText = "<b>" + feature.properties.nombre + "<br>";
layer.bindPopup(popupText);
category = feature.properties.tipo;
// Initialize the category array if not already set.
if (typeof categories[category] === "undefined") {
categories[category] = L.layerGroup().addTo(map);
layersControl.addOverlay(categories[category], category);
}
categories[category].addLayer(layer);
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
}));
Actually it comes from one of your answer on another post ghybs.

Dont want update charts dc.js

I have chart when page load. I see normal charts with data:
Ids,Dates,Values
Бар,2018-12-21,224
Бар,2018-12-22,352
Бар,2018-12-23,61
Бар,2018-12-24,379
Бар,2018-12-25,78.2
Бар,2018-12-26,0
Бар,2018-12-27,0
Бар,2018-12-28,0
Бар,2018-12-29,0
Бар,2018-12-30,0
Бар,2018-12-31,0
Бар,2019-01-01,0
Бар,2019-01-02,0
Бар,2019-01-03,0
Бар,2019-01-04,0
Бар,2019-01-05,270
Бар,2019-01-06,0
Бар,2019-01-07,0
Бар,2019-01-08,0
Бар,2019-01-09,0
Бар,2019-01-10,0
Бар,2019-01-11,0
Бар,2019-01-12,0
Бар,2019-01-13,0
Бар,2019-01-14,0
Бар,2019-01-15,0
Бар,2019-01-16,0
Бар,2019-01-17,0
Бар,2019-01-18,0
Бар,2019-01-19,0
Бар,2019-01-20,0
But if I send ajax chart is empty, but have a data, and if I load page with this data all are correct, only ajax destroy chart:
Ids,Dates,Values
Бар,2018-11-21,178
Бар,2018-11-22,256
Бар,2018-11-23,226
Бар,2018-11-24,570
Бар,2018-11-25,266
Бар,2018-11-26,398
Бар,2018-11-27,0
Бар,2018-11-28,15
Бар,2018-11-29,80
Бар,2018-11-30,118
Бар,2018-12-01,41
Бар,2018-12-02,365
Бар,2018-12-03,180
Бар,2018-12-04,187
Бар,2018-12-05,38
Бар,2018-12-06,82
Бар,2018-12-07,390
Бар,2018-12-08,177
Бар,2018-12-09,359
Бар,2018-12-10,236
Бар,2018-12-11,7
Бар,2018-12-12,34
Бар,2018-12-13,478
Бар,2018-12-14,173
Бар,2018-12-15,290
Бар,2018-12-16,453
Бар,2018-12-17,52
Бар,2018-12-18,334
Бар,2018-12-19,0
Бар,2018-12-20,122
My js code:
$(document).ready(function() {
$('.js_dashboard').focus(function() {
allPostDataForOne($(this));
});
$('.js_dashboard').parents('.container').find('.js_dc_components').find('.js_data_graph').each(function(index, value) {
renderBar(dc.barChart("#js_graphic_" + index), d3.csv.parse(d3.select(value).text()));
});
});
function allPostDataForOne(elem) {
var table = elem.parents('.container').find('.js_main_dasboard');
$.ajax({
url: '/../index/total' + $('.js_suffix').val(),
type: 'POST',
data: 'date=' + elem.val(),
success: function(data) {
table.html($($(data)).find('.js_main_dasboard').html());
table.parents('.container').find('.js_dc_components').find('.js_data_graph').each(function(index, value) {
$($(data)).find('.container').find('.js_dc_components').find('.js_data_graph').each(function(index_res, value_res) {
if (index === index_res) {
value = value_res;
}
});
renderBar(dc.barChart("#js_graphic_" + index), d3.csv.parse(d3.select(value).text()));
});
},
})
}
function renderBar(chart, experiments) {
var start_date = new Date($('.js_start_date').val());
var end_date = new Date($('.js_end_date').val());
var format = d3.time.format("%Y-%m-%d");
experiments.forEach(function(x) {
x.Values = +x.Values;
});
var ndx = crossfilter(experiments);
var runDimension = ndx.dimension(function(d) {
return new Date(d.Dates);
});
var runGroup = runDimension.group().reduceSum(function(d) {
return d.Values;
});
chart
.width(750)
.height(300)
.x(d3.time.scale().domain([start_date, end_date]))
.brushOn(false)
.yAxisLabel(experiments[0]['Ids'])
.xAxisLabel("Date")
.dimension(runDimension)
.mouseZoomable(true)
.group(runGroup)
.title(function(d) {
return d.key.getFullYear() + '-' + parseInt(d.key.getMonth() + 1) + '-' + d.key.getDate() + ': ' + d.value;
})
chart.xUnits(function() {
return experiments.length;
});
chart.render();
}
I can't understand how to correctly update charts. I saw many quations but i cant understand how they update transform in my code.

How to use Jasmine/Javascript for anonymous functions

I've spent a lot of time trying to figure out how to go inside anonymous functions in jasmine.
Sample of method:
numerateColumns: function (rows) {
rows.each(function () {
var $row = $(this);
$row.children().each(function (index) {
var $cell = $(this);
$cell.addClass('column-' + (index + 1));
});
});
}
Try to test with:
it("[TEST] Should call each method.", function () {
// setup
var rows = {
each: function () {
return {
children: function () {
return {
replaceWith: function () {
return null;
}
};
}
};
}
};
spyOn(rows, 'each').and.callThrough();
// method under test
module.numerateColumns(rows);
// expectations
expect(rows.each).toHaveBeenCalled();
});
But coverage test shows me that code of method is read only in first line (rows.each).
How to force it to read all the code inside (function() {}) ?
Why you want to test jQuery? It works perfectly, if not - some tests probably it will catch before new version publication.
function numerateColumns($rows) {
$rows.each(function() {
var $row = $(this);
$row.children().each(function(index) {
var $cell = $(this);
$cell.addClass('column-' + (index + 1));
});
});
}
describe('Iterate over columns`', function() {
var mockRows
beforeEach(function() {
mockRows = $('<div><div></div></div>')
})
it("calls .each() on passed jQuery collection", function() {
spyOn($, 'each').and.callThrough();
expect($.each).not.toHaveBeenCalled();
numerateColumns(mockRows);
expect($.each).toHaveBeenCalled();
});
it("adds CSS class to each child", function() {
var column = $(mockRows[0]).find('div');
expect(column.hasClass('column-1')).toBeFalsy()
numerateColumns(mockRows);
expect(column.hasClass('column-1')).toBeTruthy()
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
What you can test - it is extracted business logic that is independent to jQuery itself.

show percentage in d3 pie chart

currently my pie chart in d3 shows the sum of numbers,i want percentage instead .
for eg: currently i have a pie chart for how many people submitted application who visited our site. our current pie chart shows like this : people submitted 17,000 and people didn't submitted-10,000
but i need this in percentage also. how can i get that.
please find the pie code below and let me know what changes do i need to make this work. I am new to JavaScript and D3.
ko.bindingHandlers.pieChart = {
init: function (element, valueAccessor) {
var _options = valueAccessor();
var _data = _options.transformer(_options.data);
$(element).css("marginLeft", "auto");
$(element).css("marginRight", "auto");
if (typeof _options.maxWidth != "undefined") {
var _max = _options.maxWidth * 1;
$(element).width(Math.min($(element).parent().width(), _max));
}
if ($(element).find("svg").length > 0 && _data.length == 0) {
$(element).find("svg").empty();
}
if (_data.length > 0 && isNaN(_data[0].value)) {
_data = [];
$(element).find("svg").empty();
}
if ($(element).is(":visible")) {
nv.addGraph(function () {
var _chart = nv.models.growingPieChart()
.x(function (d) {
return d.label
})
.y(function (d) {
return d.value
})
.height($(element).width())
.showLabels(true).showLegend(false)
.tooltipContent(function (key, y, e, graph) {
return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' + y + '</p>'
});
var _d3 = ($(element).find("svg").length > 0) ? d3.select($(element).find("svg")[0]) : d3.select($(element)[0]).append("svg");
_d3.datum(_data)
.transition().duration(150)
.each("end", _options.onComplete != null ? _options.onComplete : void(0))
.call(_chart);
if (_options.fqs) {
$.each(_options.fqs(), function (cnt, item) {
if (item.id() == _options.data.widget_id && item.field() == _options.field()) {
_chart.selectSlices($.map(item.filter(), function (it) {
return it.value();
}));
}
});
}
$(element).data("chart", _chart);
var _resizeTimeout = -1;
nv.utils.windowResize(function () {
window.clearTimeout(_resizeTimeout);
_resizeTimeout = window.setTimeout(function () {
_chart.update();
}, 200);
});
$(element).on("forceUpdate", function () {
_chart.update();
});
$(element).height($(element).width());
var _parentSelector = typeof _options.parentSelector != "undefined" ? _options.parentSelector : ".card-widget";
$(element).parents(_parentSelector).on("resize", function () {
if (typeof _options.maxWidth != "undefined") {
var _max = _options.maxWidth * 1;
$(element).width(Math.min($(element).parent().width(), _max));
}
$(element).height($(element).width());
_chart.update();
});
return _chart;
}, function () {
var _d3 = ($(element).find("svg").length > 0) ? d3.select($(element).find("svg")[0]) : d3.select($(element)[0]).append("svg");
_d3.selectAll(".nv-slice").on("click",
function (d, i) {
if (typeof _options.onClick != "undefined") {
chartsUpdatingState();
_options.onClick(d);
}
});
});
}
},
update: function (element, valueAccessor) {
var _options = valueAccessor();
var _data = _options.transformer(_options.data);
var _chart = $(element).data("chart");
if (_chart) {
var _d3 = d3.select($(element).find("svg")[0]);
_d3.datum(_data)
.transition().duration(150)
.each("end", _options.onComplete != null ? _options.onComplete : void(0))
.call(_chart);
if (_options.fqs) {
$.each(_options.fqs(), function (cnt, item) {
if (item.id() == _options.data.widget_id && item.field() == _options.field()) {
_chart.selectSlices($.map(item.filter(), function (it) {
return it.value();
}));
}
});
}
chartsNormalState();
}
else if (_data.length > 0) {
ko.bindingHandlers.pieChart.init(element, valueAccessor);
}
}
};
A fiddle would be useful to test this against (hint hint), but I'm pretty sure you want to change this line:
.y(function (d) {
return d.value
})
to this
.y(function (d) {
return d.value/total
})
You may have to define total. Like I said, without a jsfiddle or at least some indication of the format of your data, it's hard to determine if this is actually what's wrong or how to fix it.
Note: a pie chart of relative percentages will look exactly the same as a pie chart of the original numbers. You might be able to change the label and only the label, as follows:
return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' + y + '</p>'
to this
return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' + (y/total) + '</p>'
Hopefully both of those should work. You will have to define total, if it isn't already defined elsewhere. If not:
var total = 0;
_data.forEach(function(d){total += d.value});
Good luck!
It would be even more helpful to include information such as the library you are using and a fully reproducible example using a gist, codepen, jsfiddle, etc. I am guessing you are using hue and more specifically growingPieChart. If my guesses are correct, then you can modify your tooltipContent function similar to #Vyross answer that posted while I was typing this.
.tooltipContent(function (key, y, e, graph) {
return '<h3>' + hueUtils.htmlEncode(key) + '</h3><p>' +
(+y) / d3.sum(
d3.select(graph.container).select('g').datum(),
function(d){return d.value}
) +
'</p>'
});

Node JS - get file via AJAX and then use the data

How do I do this asynchronously?
var getData, myFunc;
getData = function() {
var data = "";
$.get("http://somewhere.com/data.xml", function(d) {
data = $("#selector", d).html();
});
return data; // does not work, because async callback not yet fired
};
myFunc = function() {
var data = getData();
// do something with data here
};
I am happy to completely re-factor to achieve what I want. I am just don't know what design pattern achieves this.
Well, you can't. You can return a promise though:
var getData, myFunc;
getData = function () {
var d = $.Deferred();
$.get("http://somewhere.com/data.xml", function (data) {
d.resolve($("#selector", data).html())
});
return d.promise();
};
getData().then(function (data) {
alert(data);
});
demo http://jsfiddle.net/W75Kt/2/

Resources