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
});
Related
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'
},
});
The markers will be added dynamically using firebase.
map.loadImage(
AddressIcon,
function(error, image) {
if (error) throw error;
map.addImage(id + 'address', image);
map.addSource(id + 'point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
features
]
}
});
map.addLayer({
'id': id + "addresses-layer",
'type': 'symbol',
'source': id + 'point',
'layout': {
'icon-image': id + 'address',
'icon-size': 1
}
});
});
draw = new MapboxDraw({
displayControlsDefault: false,
userProperties: true,
controls: {
polygon: true,
trash: true
},
});
map.addControl(draw, 'bottom-left');
map.addControl(new mapboxgl.NavigationControl());
map.addControl(new mapboxgl.FullscreenControl());
map.on('draw.create', updateDrawArea);
map.on('draw.delete', updateDrawArea);
map.on('draw.update', updateDrawArea);
const updateDrawArea = (e) => {
var data = draw.getAll();
console.log(data);
}
I have the polygon drawing system on the map. I need to get all of the added layers/markers after draw the polygon around the markers. I need to do this using mapbox-gl-js if possible. If not is there any alternatives?
Yes, it is possible through Turf.js.
Turf.js exposes functions such as pointsWithinPolygon, that allow us to specify marker points and polygon coordinates, and returns a list of markers that inside the specified polygon.
For example:
var pointsWithinPolygon = require("#turf/points-within-polygon")
const turf = require('#turf/turf');
var points = turf.points([
[-46.6318, -23.5523],
[-46.6246, -23.5325],
[-46.6062, -23.5513],
[-46.663, -23.554],
[-46.643, -23.557]
]);
var searchWithin = turf.polygon([[
[-46.653,-23.543],
[-46.634,-23.5346],
[-46.613,-23.543],
[-46.614,-23.559],
[-46.631,-23.567],
[-46.653,-23.560],
[-46.653,-23.543]
]]);
var ptsWithin = turf.pointsWithinPolygon(points, searchWithin);
console.log(ptsWithin)
You can refer to this tutorial that explains how we can use turf.js along-side mapbox-gl-draw.
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,
});
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);
}
});
}
});
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();
} });
});