Using Gmaps.map.replaceMarkers() I can replace entire marker set. But in my application I will use more than 3000 markers.
How to replace one marker or subset of markers?
This is definitely possible but because there is no rule, there is custom code to write.
Here is how I proceed generally:
I add some custom data in the marker's json, the id of the active record's object generally
I sort my markers client side in javascript variables, say you have the ids of markers you want to remove in a js array called toClear
I remove useless markers:
Coffeescript:
for marker in Gmaps.map.markers
if marker.id in toClear
Gmaps.map.clearMarker marker
I add the new one Gmaps.addMarkers new_markers_array
Related
I'm currently working on an application for making geologic maps. I'm using Ruby on Rails for my back end, React for my front end, and Postgres for the database. I am using React Leaflet to display the maps (abstracts Leaflet.js to React components). I am getting the maps from OpenTopoMap. This application is non-commercial and I have checked their terms of use to make sure I am not in violation.
I want users to be able to view a map and be able to add points and draw polygons on it (I already know how to do this part). Once they are done drawing on the map I want them to be able to save the map with whatever additions they have made. They should then be able to reopen it later and modify it.
The only way I have found to save the map is as a .png, which means it can't be edited when it is reopened.
Saving only the points/polygons and re-rendering them when a user reopens the map is an acceptable solution as long as the correct area of the map is shown when it is reopened, but I am not sure how I would go about storing this data. A user can have many maps, so solutions that only work for a single instance of map will not work in this case.
I am aware that what I have described here just duplicates the functionality of many other mapping applications. Once this part is figured out I plan to add extensive functionality that is specific to making geological maps. I have not described that functionality here because it is not relevant to my current question.
How can I save a map to PostgreSQL in a format that will allow it to be edited when reopened?
Instead of reinventing the wheel with some JSON column monstrosity look into PostGIS. Its an extension for Postgres that adds geospatial data types like points, lines and polygons. It also lets you write geospatial database queries like for example testing if a point is in a polygon or proximity searches.
For rails the the activerecord-postgis-adapter gem adds these database types:
:geometry -- Any geometric type
:st_point -- Point data
:line_string -- LineString data
:st_polygon -- Polygon data
:geometry_collection -- Any collection type
:multi_point -- A collection of Points
:multi_line_string -- A collection of LineStrings
:multi_polygon -- A collection of Polygons
This provides the building blocks to create models with geospatial attributes. Its not a magic wand that will let you stuff a map with doodles into Postgres and get something editable out and will require a significant effort in both research and implementation.
I use leaflet and leaflet.draw together to save the geoJSON from drawing polygons or dropping markers and save it to a field called coords in the database. There is a good example of it here: https://github.com/jeremygradisher/mapping-leaflet
It boils down to using leaflet.draw to draw the coordinates and then saving that data where you need it. Here is leaflet.draw: http://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html
Here I am using leaflet.draw to draw on the map and then I stringify the data and add it to a field to be saved in the database.
<script>
// Initialize the FeatureGroup to store editable layers
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Initialize and alter the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw({
draw: {
//These options make up the root object that is used when initializing the Leaflet.draw control.
position: 'topleft',
polygon: {
allowIntersection: false,
drawError: {color: '#00dd00', timeout: 1000
},
shapeOptions: {color: '#00dd00', weight: 1}, showArea: true},
polyline: false,
rectangle: {shapeOptions: {color: '#00dd00',weight: 1}},circle: false},
edit: {featureGroup: drawnItems}
});
map.addControl(drawControl);
//draw:created - Triggered when a new vector or marker has been created.
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
var shape = layer.toGeoJSON();
var shape_for_db = JSON.stringify(shape);
drawnItems.addLayer(layer);
//trying some things here
//enter in field to save to the database
document.getElementById('area_coords').value = shape_for_db;
});
As far as I understand you want to save complicated objects to the database. An user can draw lines on the map and can draw polygons and etc. Maybe using jsonb object for this problem can be your solution. Basically it's saving a JSON formatted field to database.
An example jsonb object can be like this.
{
"data": {
"type": "user_map",
"attributes": {
"user_id": "1",
"drawings": {
"points": [],
"lines": {},
"polygons": {}
}
}
}
}
You can both keep these information on user or on separate model with using has_many :maps on user model.
Links that can help you:
Example 1
Example 2
I would suggest not to think in terms of map (the rendering of spatial data) but in terms of data (a point/line/polygon with attributes). You would save each user data in tables, maybe have another map_config table that holds the map bounding box, name etc.
In you app, once you have authenticated the user, you give access to its map configurations (let him select the one to be shown) and associated data. You then display the map either using the raw vector data directly in Leaflet, Open Layers (or else), or you can pipe it through a geo server (Geoserver, Mapserver etc) for serving it as wms images, or wfs editable vector data. You zoom or restrict the displayed area to the one saved in the map configuration.
So, my idea of turning off the Geolocation functionality in an Openlayers 3.9.0 map is to have a toggle button that when is clicked it stops the tracking and removes the feature from the geolocation layer
geolocation.setTracking('false');
featuresOverlay.getSource().clear();
and then to turn it on again it turns the tracking on, adds a feature to the geolocation layer, sets its coordinates and re-centers the map
geolocation.setTracking('true');
featuresOverlay.getSource().addFeature(positionFeature);
var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
view.setCenter(coordinates);
Well, this technically does not count as turning on/off the geolocation because it removes all the visual elements, it does not actually turns on/off the API. Is there such a possibility, or the above are enough?
Sure it does, after one minor change.
Assuming that geolocation in your code references an instance of ol.Geolocation, calling geolocation.setTracking(false) will make the geolocation call clearWatch on the browsers geolocation API. The relevant code is here.
However, setTracking expects a boolean value. You send the string 'false', which is interpreted as a truthy value (since it's a non-empty string). Remove the quotation marks from the setTracking paramters, and it should work as expected.
I'm implementing a feature for users to select a list item that corresponds to a point on the map. I am currently able to set the correct map center and the zoom level but the map tiles are blank until I cause a MouseWheelZoom interaction to occur on the map. How do I get my WMTS layers to update to the new zoom level and map extent?
In principle, changing the tileUrlFunction of a WMTS source will trigger a refresh, because that clears the tile cache. If you're lucky and your WMTS server makes proper use of Etags, just using the same url function again will work:
wmtsSource.setTileUrlFunction(wmtsSource.getTileUrlFunction());
If your WMTS server just sets expire headers, you'll have to append something to the url to force the browser to refetch it. Assuming you use KVP encoding to talk to your WMTS server, you could achieve this by doing something like
var random = Math.random();
var originalTileUrlFunction = wmtsSource.getTileUrlFunction();
wmtsSource.setTileUrlFunction(function() {
return originalTileUrlFunction.apply(this, arguments) + '&' + random;
});
From the server response comes to me with an update of coordinates every 5 second. This coordinates I add to map like pins. But existing coordinates of current object not removes, it coordinates just add as new. How to update coordinates of current object and remove object that have no coordinates for now?
I use native map. If you give any simple I'll be happy
The response from the server, I receive the coordinates of users if the user is, if not - nothing comes. I need an approach without removing all the coordinates and with management (delete or update), depending on the receipt of a new member eoordinaty or delete it
Use this :
[mapView removeAnnotations:mapView.annotations]
Before adding your annotation.
Hope it works :)
I must be missing something obvious - I am basically trying to do in v2, what I think is outlined in [this SO question], except that doesn't work in v2. Specifically, Gmaps.maps is no longer defined.
I've gotten as far as figuring that if I store the marker data array that's returned when I call addMarkers in the buildMaps callback, I can use the elements of that array to delete a marker.
If I'm storing a custom attribute in the JSON that I sent to addMarkers, I can then hold on to that JSON array as well, and query for that attribute, find the index, and then hide the marker with that index in the marker data array - here's what I mean, in pseudo-code:
json_array=generate_json();
handler.build_map({}, function() { window.marker_data=handler.addMarkers(); });
indexes=find_in_json(json_array, {"type":"hotel"});
marker_data[i].hide() for i in indexes;
But this means I have the same conceptual data in two places - is there a better way to do this that avoids managing the "model" of the marker in two separate arrays?
I understand your concern.
What I do is to merge data in this case, check http://apneadiving.github.io/ there is an example (check sidebar section)
var markers = handler.addMarkers(json_array);
_.each(json_array, function(json, index){
json.marker = markers[index];
});