Data driven styling errors using client-side join - Mapbox GL JS - javascript

I have implemented a client-side join from a GitHub based CSV to a Mapbox tileset using a Papa-parse promise function, similar to how it is implemented in: Data Joins : Mapbox JS.
The promise is fulfilled and the data is stored correctly, the outlines of the regions I am trying to visualise show, but there is an issue with data-driven styling with the "interpolate", ['linear'] parameters I am trying to use, from my past experience. The 'accessibilityOutline' ID layer shows its data correctly, so it is confusing to why this is happening.
An error keeps coming up declaring
"Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values."
I am wondering if anyone else has had this problem, and the way it was overcome. Any help would be grateful.
The code implemented is below, this is all based off the link above. The data is read in correctly and through debug testing I can see that all the data is in the correct format as the
dynamicTyping: true,
is present in the Papa.parse function. However, mapbox looks like it is unable to read this data.
function papaPromise(url) {
return new Promise(function(resolve,reject) {
Papa.parse(url, {
download: true,
header: true,
skipEmptyLines: true,
complete: resolve,
dynamicTyping: true,
});
});
}
const accessibilityCSV = papaPromise("some random url of data");
const mapContainer = useRef();
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainer.current,
style: "mapbox://styles/mapbox/outdoors-v11",
center: [-2.597, 53.39],
zoom: 9.5,
});
map.on("load", () => {
accessibilityCSV.then(function (results) {
console.log(results.data);
results.data.forEach((row) => {
map.setFeatureState({
source: 'lsoa_ultra_generalised-3gznbd',
sourceLayer: 'lsoa_ultra_generalised-3gznbd',
id: row.lsoa_code
}, {
lsoa_name: row.lsoa_name,
Total_LSOA_population: row.Total_LSOA_population,
LSOA_population_low_income: row.LSOA_population_low_income,
airport_jt60: row.airport_jt60,
airport_jt90: row.airport_jt90,
seaport_jt60: row.seaport_jt60,
seaport_jt90: row.seaport_jt90,
city_jt60: row.city_jt60,
city_jt90: row.city_jt90,
visitor_attraction_jt60: row.visitor_attraction_jt60,
visitor_attraction_jt90: row.visitor_attraction_jt90,
beach_jt60: row.beach_jt60,
beach_jt90: row.beach_jt90,
national_park_jt60: row.national_park_jt60,
national_park_jt90: row.national_park_jt90,
biz_60: row.biz_60,
biz_90: row.biz_90,
NPIER_60: row.nPIER_60,
NPIER_90: row.nPIER_90,
uni_places_60: row.uni_places_60,
uni_places_90: row.uni_places_90
},
);
});
});
map.addSource('northOutline', {
type: "vector",
url: "vectorURL"
})
map.addSource("accessibilitySource", {
type: "vector",
url: "vectorURL",
promoteId: 'LSOA11CD'
});
map.addLayer({
id: 'accessibility',
type: 'fill',
source: 'accessibilitySource',
'source-layer': 'lsoa_ultra_generalised-3gznbd',
paint: {
"fill-color":[
"interpolate",
['linear'],
['number', ["feature-state","Total_LSOA_population"]],
0,
"#fee5d9",
2075,
"#fcae91",
4150,
"#fb6a4a",
6225,
"#de2d26",
8300,
"#a50f15",
/* other */, "#ccc",
],
},
});
map.addLayer({
id:'accessibilityOutline',
type:'line',
source: 'accessibilitySource',
'source-layer': 'lsoa_ultra_generalised-3gznbd',
paint: {
"line-color": '#000000'
},
});

Related

FullCalendar not showing extraParams

I am having some problems retrieving these from my string
here is my script, taken from the website..
events: {
url: '/CalendarManager/Findall',
method: 'GET',
extraParams: {
custom_param1: 'customerName',
custom_param2: 'description'
},
failure: function () {
alert('there was an error while fetching events!');
},
eventRender: function (event, element) {
element.qtip({
content: event.custom_param1,
content: event.custom_param2
});
}
},
UPDATE: 12/24/2020
To answer questions below.. I am using 5.3.2 version. I can use this as well and it will bring back everything but the custom parameters.
events: '/CalendarManager/Findall',
I am using Json pulling from DB - Below is the code..
public ActionResult FindAll()
{
return Json(db.GetEvents.AsEnumerable().Select(e => new
{
id = e.CompanyId,
companyName = e.CompanyName,
title = e.Title,
description = e.Description,
allDay = e.AllDay,
start = e.StartDate.ToString("yyyy-MM-ddTHH:mm:ss"),
end = e.EndDate.ToString("yyyy-MM-ddTHH:mm:ss"),
color = e.Color
}).ToList(), JsonRequestBehavior.AllowGet);
}
I changed the version I was using and that is when the extras did not show up. So I added what I thought the documentation said to use.
Adding the extra Params after the url did not work..
UPDATE:
I read through the suggested. I guess I am still not understanding or maybe not getting "Where I am supposed to put the code".
I believe I need to use eventContent. I also did use the console.log(info.event.extendedProps.companyName); Which is great, it does show up in the console window, However i need it on the calendar not in the console window. FullCalendar's examples could be a little better!
Here is what I did but still does not show on the calendar.
eventDidMount: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
console.log(info.event.extendedProps.companyName);
},
eventSources: [{
url: '/CalendarManager/Findall',
failure: function () {
alert('there was an error while fetching events!');
},
}],
eventContent: function (arg) {
html: arg.event.extendedProps.companyName
}
I did add some stuff in there to produce just a bubble when hovered over with this info but it does not work either.
Thank You!
UPDATE: 12/27/2020 Working Code
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prevYear,prev,next,nextYear today',
center: 'title',
right: 'dayGridMonth,dayGridWeek,dayGridDay,listWeek'
},
initialView: 'dayGridMonth',
navLinks: true, // can click day/week names to navigate views
editable: true,
dayMaxEvents: true, // allow "more" link when too many events
themeSystem: 'bootstrap',
selectable: true,
selectMirror: true,
//Random default events
//events: '/CalendarManager/Findall',
eventDidMount: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
console.log(info.event.extendedProps.companyName);
},
events: {
url: '/CalendarManager/Findall',
failure: function () {
alert('there was an error while fetching events!');
},
},
eventContent: function (arg) {
return { html: arg.event.title + '<br>' + arg.event.extendedProps.companyName + '<br>' + arg.event.extendedProps.description };
}
});
calendar.render();
Thank you for all your help!
First, let me know what kind of version of fullcalendar you are using.
fullcalendar v5.5 doesn't provide eventRender.
And extraParams is not what you want to show. It is the query params which attach after the request url, like http://example.com/CalendarManager/Findall?custom_param1=customerName&....
If you want to use extend event props then you should parse them as extendProps.
And you should use Event Render Hooks rather than eventRender if you are using the latest version.
How to fix:
Anyway, you should use function, not an object.
You can use events (as a function)
function( fetchInfo, successCallback, failureCallback ) { }
You can also use events (as a json feed)
var calendar = new Calendar(calendarEl, {
events: '/myfeed.php'
});
If you are going to use object rather than function, then you can use eventSources
And if you want to handle the success response, then use eventSourceSuccess function
Here is an example (using fullcalendar v5.5):
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'listWeek',
loading: function(bool) {
if (bool) {
$("#dashboard-calendar-column .pre-loader").show();
} else {
$("#dashboard-calendar-column .pre-loader").hide();
}
},
// get all events from the source
eventSources: [{
url: '/CalendarManager/Findall',
method: 'GET',
failure: function() {
document.getElementById('script-warning').style.display = 'block'
}
}],
// convert the response to the fullcalendar events
eventSourceSuccess: function(content, xhr) {
var events = [];
content.events.value.map(event => {
events.push({
id: event.id,
allDay: event.isAllDay,
title: event.subject,
start:event.start.dateTime,
end: event.end.dateTime,
// The followings are what you want to add as extended
custom_param1: 'customerName',
custom_param2: 'description',
// Or you could add them to the extendedProps object
extendedProps: {
custom_param1: 'customerName',
custom_param2: 'description',
description: event.bodyPreview,
...
},
// You can check fullcalendar event parsing
...
})
})
return events;
},
eventDidMount: function (arg) {
// remove dot between the event titles
$(arg.el).find('.fc-list-event-graphic').remove();
// You can select the extended props like arg.event.custom_param1 or arg.event.extendProps.custom_param1
...
},
});
calendar.render();
})
Hope this would help you.
You can use extraParams using eventSources if you are using fullcalendar v5.
eventSources: [{
url: '/CalendarManager/Findall',
method: 'POST',
extraParams: {
custom_param1: 'customerName',
custom_param2: 'description'
}
...
}]
You should use POST rather use GET, then it will work.

mapbox ForEach function

When pulling in data from a geojson file that is stored online. The forEach function can not read the features I have set in the geojson file. Below is part of the code.
map.on('load', function() {
// Add a GeoJSON source containing place coordinates and information.
map.addSource('orders', {
type: 'geojson',
data: ordersjson,
});
map.addLayer({
id: "layerID",
type: "symbol",
source: 'orders',
layout: {
"icon-image": "circle" + "-15",
"icon-allow-overlap": true,
},
});
map.getLayer('layerID').features.forEach(function(feature) {
var earthquakeID = feature.properties['primary ID']
});
The layer itself does not have any data at all. What you need is to get the source that holds the data. The layer is just for style definitions.
What you want is something like this:
map.getSource('orders')._data.features.forEach(function(feature) {
// do something
});

Add Annotation to Openseadragon

var viewer = OpenSeadragon({
id: "openseadragon1",
prefixUrl: "images/openseadragon/",
showNavigator: true,
navigatorPosition: "BOTTOM_RIGHT",
tileSources: '/fcgi-bin/iipsrv.fcgi?Deepzoom=<?=$plink?>.jp2.dzi',
crossOriginPolicy: 'Anonymous',
zoomInButton: "zoom-in",
zoomOutButton: "zoom-out",
homeButton: "home",
fullPageButton: "full-page"
});
anno.makeAnnotatable(viewer);
$.ajax({
url: "handlers/H_AnnotationHandler.php",
data: "case_id=<?=$case_id?>&plink=<?=$plink?>&mode=get",
type: "post",
dataType: "json",
success: function(response) {
if (!response.error) {
for (var i=0; i<response.annots.length; i++) {
console.log(response.annots[i].comment);
anno.addAnnotation({
text: response.annots[i].comment,
shapes: [{
type: 'rect',
geometry: {
x: response.annots[i].rect_x,
y: response.annots[i].rect_y,
width: response.annots[i].rect_w,
height: response.annots[i].rect_h
}
}]
});
}
} else {
console.log(response.error);
}
}
});
I can add annotation live : http://annotorious.github.io/demos/openseadragon-preview.html
After user added the annotation, I store in my database. When the user refresh the page, I am loading saved datas from database using ajax call (H_AnnotationHandler.php). Returning data is true, but I could not draw annotation on jpeg2000 image using anno.addAnnotation, how can I draw it ?
Reference : Add annotations API.
You are missing src attribute in anno.addAnnotation method, the thing is that I don't really know what value should go there, there is nothing in documentation about that, the only thing I could find in internet is this plugin:
https://github.com/dgutman/OpenSeadragon-Plugins/tree/master/annotationState_Code
You could try that instead.
EDIT
I actually managed to attach event programatically on the demo page, the open sea dragon module there is registered as a dzi://openseadragon/something, knowing this you can invoke the function
anno.addAnnotation({
src : 'dzi://openseadragon/something',
text : 'My annotation',
shapes : [{
type : 'rect',
geometry : { x : 0.8, y: 0.8, width : 0.2, height: 0.2 }
}]
});
from console (or in your code within the ajax-success loop) and it will be added to the image. Yet, the naming method is pretty... well, I found this in the source code:
annotorious.mediatypes.openseadragon.OpenSeadragonModule.prototype.getItemURL = function(item) {
// TODO implement something decent!
return 'dzi://openseadragon/something';
}
so be assured that this might change in future.
Since you didn't share your code I tried to set it up here: https://jsfiddle.net/peLokacs/3/, please do the necessary changes so I can see the annotations. Also I get a "Annotorious does not support this media type in the current version or build configuration." error, If you managed to save the annotations, then you probably know how to fix that too.
var viewer = OpenSeadragon({
id: "openseadragon-1",
prefixUrl: "https://neswork.com/javascript/openseadragon-bin-2.1.0/images/",
//tileSources: "https://openseadragon.github.io/example-images/highsmith/highsmith.dzi",
tileSources: { type: 'legacy-image-pyramid', levels: [{ url: '0001q.jpg', height: 889, width: 600 }, { url: '0001r.jpg', height: 2201, width: 1485 }, { url: '0001v.jpg', height: 4402, width: 2970 }]},
showNavigator: true,
});

Javascript page re-route after d3.js event

I experimenting with d3.js and how to implement the framework.
At this stage of experimental implementation, I would like to make the filled Countries create alerts when I click them.
The ultimate goal is to change the alert to a page re-route, using the country name to decide which page it gets routed to.
In depth explanations are greatly appreciated.
Here is the code:
var map = new Datamap({
element: document.getElementById('container'),
fills: {
PARTS:'green',
defaultFill: 'black'
},
data: {
USA: {
fillKey: 'PARTS'
},
IRL: {
fillKey: 'PARTS',
}
},
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography, data) {
if(data.fillKey=='PARTS'){
alert(geography.properties.name);
}
});
}
});

JvectorMap Region Selection

I am trying to reuse the region selection feature of JVectorMap. I am using a custom map (js) file. I have tested it in and it works fine for region selection.
Now I need to pass the regions which are selected by the user to the back end vb code. In this case maps.getSelectedRegions() gives an array of the user selected regions. I am not clear on how to pass a javascript array to back end vb code. The window.localstorage as how it is given in the example don't seem to work out here. Can somebody help me out on how this an be done?
This is the link of JVectorMap Region Selection - http://jvectormap.com/examples/regions-selection/
Following is the code I have used so far.
<script>
$(function(){ var maps; maps = new jvm.WorldMap({
container: $('#map'),
map: 'xyz_map',
regionsSelectable: true,
regionStyle: {
initial: {
fill: '#B8E186'
},
selected: {
fill: '#F4A582'
}
},
series: {
},
onRegionSelected: function(){
if (window.localStorage) {
window.localStorage.setItem(
'jvectormap-selected-regions',
JSON.stringify(maps.getSelectedRegions())
);
}
}
}); maps.setSelectedRegions( JSON.parse( window.localStorage.getItem('jvectormap-selected-regions') || '[]' )
); });
</script>
Thanks in advance
Sina
Managed to get a solution for this myself. You can add a hidden control in your asp code and assign the variable to this control.
$(function(){ var maps,temp; var hiddenControl = '<%=
inpHide.ClientID %>'; maps = new jvm.WorldMap({
container: $('#map'),
map: 'xyz_map',
regionsSelectable: true,
regionStyle: {
initial: {
fill: '#B8E186'
},
selected: {
fill: '#F4A582'
}
},
series: {
},
onRegionSelected: function(){
document.getElementById(hiddenControl).value=maps.getSelectedRegions();
} });
});

Categories