I'm developping a map using mapbox gl js, my issue is the following:
I have 1 source and I apply 1 setData on this source with a geojson collection of points -> fine
I want to update one position for one feature (point) of this featurecollection
I do querySourceFeatures and I get an array of features -> fine
I detect the feature I want to modify and I modify the lat-long accordingly -> fine
I would like to apply the whole setData with the modify feature to redraw but ...
Here is the problem, how do I go from the array of features (one is modified) to a feature collection compatible with setData ... ?
I'm confused why (or what) there is not a straight path to do that ... What do I miss here?
can you help me please?
thanks,
Olivier
finally, I rebuild the featureCollection "manually" in a separate function ... I though it would not be an optimized solution but at the end, reveals quite straight ...
function build_featureCollection_from_array(parray) {
lv_fc = {};
lv_fc.type = "FeatureCollection";
lv_fc.features = parray;
return lv_fc;
}
we are using OpenLayers 4.6.4 with the ol-ext extension in order to show beautiful looking clusters. That is working fine so far, but we need to link each cluster with custom informations (like putting a simple field into the cluster object) and once the cluster is clicked on the map, i want to retrieve it with the arguments delivered in the callback.
I was not able to find a simple example on putting custom fields on a cluster and retrieving them once i click them on the map.
The event i add my listener is handled by ol.interaction.SelectCluster from ol-ext
Any ideas?
You cannot change the cluster features so easily, but that's actually not necessary to get information about it.
Cluster is just a layer source which clusters (who would have guessed) an underlaying source. It creates Features, which in turn have the represented Features stored in a property features.
The ol-ext example demonstrates how to read the contained features:
var selectCluster = new ol.interaction.SelectCluster(.....);
selectCluster.getFeatures().on(['add'], function (e)
{ var c = e.element.get('features');
if (c.length==1)
{ var feature = c[0];
$(".infos").html("One feature selected...<br/>(id="+feature.get('id')+")");
}
else
{ $(".infos").text("Cluster ("+c.length+" features)");
}
})
Without any interaction, you could do this:
map.on('singleclick', function(evt) {
const feature = map.forEachFeatureAtPixel(
evt.pixel,
function(someFeature){ return someFeature; }, // stop at the very first feature
);
const containedFeatures = feature.get('features');
});
I have a working application here: http://dola.colorado.gov/gis-cms/sites/default/files/html/census2000v2.html
I'm using the Javascript API with ArcGIS Online. I have a bunch of layers loaded and pre-symbolized in an AGOL 'Web Map'.
I'd like to be able to customize the symbology of each layer dynamically using javascript. I'd ideally like to use a renderer and be able to create a different symbology for each demographic variable.
I've run into a major brick wall. To be able to change the symbology, I need to be able to iterate through graphics in a feature set - yet I have no idea where to get a feature set object from. All the examples I see use 'Feature Layers' loaded through URLs.
I think first you need to get the layer from the webmap:
var featureLayer = mapObject.getLayer(layerName)
Then you can query the featurelayer, which will return a featureSet.
Here is an example:
var query = new esri.tasks.Query();
query.outFields = ["*"];
featureLayer.queryFeatures(query, function(featureSet) {
//do something with the featureSet here!
});
First: I try to remake a Website called regionalkarten.com
It's a German publisher of Maps. This page uses the Google API v2 to show our custom maps.
My Job is to update the Page to API v3.
Now I found the jQuery GoMap Plugin and I try to use it, but it doesn't seem to support custom maps.
I tried to define a Overly with the custom Map
var ehsTypeBOptions =
{
getTileUrl: function(coord, zoom)
{
var x = coord.x;
var y = coord.y;
return "http://regionalkarten.com/_map/ehs_village_maps/is_maps/z"+zoom+"/"+coord.y+"/"+coord.x+".png";
},
tileSize: new google.maps.Size(256, 256),
};
and load it into the map with:
map.overlayMapTypes.insertAt(0, new google.maps.ImageMapType(ehsTypeBOptions));
That works fine without GoMap. So I tried:
$.goMap.overlayMapTypes.insertAt(0, new google.maps.ImageMapType(ehsTypeBOptions));
and guess what, it didn't work :(
GoMaps Webpage and Google aren't very helpful. Keep in mind that I have to load the custom map into an overlay. I need the real google maps behind the overlay because our maps are not gapless.
I hope you got some ideas or experience with GoMap.
Thank you.
$.goMap does not return the native google.maps.Map-instance, so you can't use the Maps-API-methods there.
The google.maps.Map-instance may be accessed via $.goMap.map .
Beyond that: I would suggest not to use this library, there haven't been any updates since 1 year, and this all can be done without any additional library.
More important: before you continue working with ImageMapType, this is not the right MapType for you, because it appears that the TileServer don't serve tiles for the complete world.
When the user pans or zooms so that a area is in viewport where no tile is available, this area would be shown as a gray space. You better use a Overlay MapType and set the background-image of the overlays to the TileUrl(additionally you may use a condition that checks if a Tile is available at all to reduce unnecessary request to the tile-server)
I need good examples and best practices on program architecture.
I'm trying to build a JS UI for an app that works with Google.Maps. In the 1st draft, user should be able to draw geometric shapes on the map in a way similar to G.M. Then the shapes are sent through AJAX and the response is displayed.
Problem is that the code got complicated just with polygons editing.
Inspired by Joel's "Duct-tape Programmer", I tried to sketch a straightforward code that makes actions and switches event handlers, to avoid big if-else trees. "New poly" button creates an observer for map.onclick, changes event handlers for other buttons or hides them, and hides itself, etc.
The downside of this approach is that data handling code is mixed with interface. A code that creates a div container to display the data on the new polygon stands next to the code that deals w/ G.M or w/ the shape data. If I want to revise the UI, I'll need to process the WHOLE app.
I could review it later and move this UI-generating code elsewhere, but then came my lead programmer. He instead insisted on "messaging" approach: a simple event system where objects subscribe to events and fire them. Interface code can be perfectly isolated from data handling and talking to G.M, but now each listener has to double-check if this message is to it.
For example, clicking on a poly on a map must highlight it and start editing. But not if another poly is being drawn. So, some are-you-talking-to-ME?-code is necessary everywhere.
I'll appreciate good examples of UI architecture approaches.
The event handling idea suggested to you is a good approach.
Here's some more ideas:
Make the shape drawing thing a component
The shape drawing component sends events to other code, to react to stuff like "editing" or "clicked"
This component could also handle the editing part - It sends "clicked" event to controller, controllers tells the component to go into edit mode
While in edit mode the component would not send normal "clicked" events until the editing was closed, avoiding your problem of having to check
In general, it's a good idea to have a "view" layer which simply deals with displaying the data and sending events about user actions on that data (ie. clicks, etc.) to a "controller" layer, which then decides what to do - for example it could decide to change the view into editing mode.
I don't know if this is beside the point. But I use this as a temple for all my javascript projects.
(function () {
var window = this,
$ = jQuery,
controller,
view,
model;
controller = {
addEventForMenu : function () {
// Add event function for menu
}
};
view = {
content : {
doStuff : function () {
}
},
menu : {
openMenuItem : function () {
}
}
};
model = {
data : {
makeJson : function () {
// make json of string
},
doAjax : function () {
},
handleResponse : function () {
}
}
}
$.extend(true, $.view, view);
})();
The good thing here is that it's only the view object that is extended to the DOM, the rest is kept inside the anonymous scope.
Also in bug project i create on of these files for each part ie, map.js, content.js, editor.js
If you just mind the naming of your methods in the view object you can have as many files as you like during development. When the project is set in to a production environment I just make it one file and minify it.
..fredrik
In short publisher-subscriber paradigm works well to make geometric shapes. First make command-line which primitive is base polygon publisher publishes. Canvas object seems obvious here to paint, usual method repaint() for updating the client view (eventdriven programming normally in C you can review eg opengl or glut eventdriven graphics), combined with the so-so gmap API I too use, publisher-subscriber pattern or factory are good design patterns whatever graphics implementation. tricky gmaps specific thing is latitude and longitude switch places in the array between json and persistence layer, there's no serverside reverse geocoding yet, naming is kinda inconsistent, and for multilingua apps names both change relative user human language and are doubled (Paris in Text, Paris in France...),. Look if you like my going implementation, registers geographic names and spatial coordinated relative user with geoip worldwide
function wAdd(response){
map.clearOverlays();
if(!response||response.Status.code!=200){
}
else{
try{
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
try{
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
try {
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.CountryName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
place=response.Placemark[0];
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml(''+place.address+'');
}
} }
}map.addOverlay(geoXml);
}
i would recommend having few object variables containing the state (0, drawing, editing, ... any other required) - this would help you deciding whether to allow event handling or just bury it if for example drawing is done and clicking on editable polygone happens.
as for the UI - I am not sure if your question is aimed at you - developing the script or at the user as you are mixing two things here.
keep in mind that for a user everything should be as simple as possible: if he is editing, don't allow him to draw. if he is drawing, don't allow him to edit (overlapping of polygons could occur). however - allow user quickly to switch from editing (e.g. right click?) to drawing - or in other words cancel the current state.
The first thing I would do is create a service that wraps over the google API. This is so that later if you need to change mapping services (windows maps or yahoo maps). Then you can put a facade over the google service. Then you might want to put some wrappers over your service and split it up into a view(output) and model(input) and manage this with controllers/presenters. Check into Model View Controller / Model View Presenter / Presenter First / Humble Dialog on Wikipedia. It should discuss the seperation that your looking for. Also Martin Fowler web page goes into presentation patterns. You should check out my old blog ugly-lisp-code. I have references to event driven/event messaging.
If you have a one-to-one pub/sub just store an event-handler(closure/lambda/first-order-function) in the object that is going to fire the event.
If you have a one-to-many pub/sub then you will need a more complex object to store your closures.
LOL! Right now I've been looking at this same exact issue. I'm going to be writing about using a presenter-first in JavaScript on my blog. A bare bones start on presenter and model.
[edit] you might want to check out this stackoverflow question. One of the answer has a link to separating concerns into MVC. The link is on A List Apart.