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];
});
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.
dartques = {'Color':[], 'Fruits':[], 'Hobbies':[]};
How to access the values using index in map?
I need to access only key or value using index.
Just like we do in list
=>list[1]
you can get it like this
var element = dartques.values.elementAt(0);
also for Dart 2.7+ you can write extension function
extension GetByKeyIndex on Map {
elementAt(int index) => this.values.elementAt(index);
}
var element = dartques.elementAt(1);
For accessing the values by index, there are two approaches:
Get Key by index and value using the key:
final key = dartques.keys.elementAt(index);
final value = dartques[key];
Get value by index:
final value = dartques.values.elementAt(index);
You may choose the approach based on how and what data are stored on the map.
For example if your map consists of data in which there are duplicate values, I would recommend using the first approach as it allows you to get key at the index first and then the value so you can know if the value is the wanted one or not.
But if you do not care about duplication and only want to find a value based on Index then you should use the second approach, as it gives you the value directly.
Note: As per this Answer By Genchi Genbutsu, you can also use Extension methods for your convenience.
Important:
Since the default implementation for Map in dart is LinkedHashmap you are in great luck. Otherwise Generic Map is known for not maintaining order in many programming languages.
If this was asked for any other language for which the default was HashMap, it might have been impossible to answer.
You can convert it to two lists using keys and values methods:
var ques = {'Color':['a'], 'Fruits':['b'], 'Hobbies':['c']};
List keys = ques.keys.toList();
List values = ques.values.toList();
print (keys);
print (values);
The output:
[Color, Fruits, Hobbies]
[[a], [b], [c]]
So you can access it normally by using keys[0], for example.
I have proven to myself that I can insert text into a Google Docs document using this code:
function appendToDocument() {
let offset = 12;
let updateObject = {
documentId: 'xxxxxxx',
resource: {
requests: [{
"insertText": {
"text": "John Doe",
"location": {
"index": offset,
},
},
}],
},
};
gapi.client.docs.documents.batchUpdate(updateObject).then(function(response) {
appendPre('response = ' + JSON.stringify(response));
}, function(response) {
appendPre('Error: ' + response.result.error.message);
});
}
My next step is to create an entire, complex document using the api. I am stunned by what appears to be the fact that I need to maintain locations into the documents, like this
new Location().setIndex(25)
I am informing myself of that opinion by reading this https://developers.google.com/docs/api/how-tos/move-text
The document I am trying to create is very dynamic and very complex, and handing the coding challenge to keeping track of index values to the api user, rather than the api designer, seems odd.
Is there an approach, or a higher level api, that allows me construct a document without this kind of house keeping?
Unfortunately, the short answer is no, there's no API that lets you bypass the index-tracking required of the base Google Docs API - at least when it comes to building tables.
I recently had to tackle this issue myself - a combination of template updating and document construction - and I basically ended up writing an intermediate API with helper functions to search for and insert by character indices.
For example, one trick I've been using for table creation is to first create a table of a specified size at a given index, and put some text in the first cell. Then I can search the document object for the tableCells element that contains that text, and work back from there to get the table start index.
Another trick is that if you know how many specific kinds of objects (like tables) you have in your document, you can parse through the full document object and keep track of table counts, and stop when you get to the one you want to update/delete (you can use this approach for creating too but the target text approach is easier, I find).
From there with some JSON parsing and trial-and-error, you can figure out the start index of each cell in a table, and write functions to programmatically find and create/replace/delete. If there's an easier way to do all this, I haven't found it. There is one Github repo with a Google Docs API wrapper specifically for tables, and it does appear to be active, although I found it after I wrote everything on my own and I haven't used it.)
Here's a bit of code to get you started:
def get_target_table(doc, target_txt):
""" Given a target string to be matched in the upper left column of a table
of a Google Docs JSON object, return JSON representing that table. """
body = doc["body"]["content"]
for element in body:
el_type = list(element.keys())[-1]
if el_type == "table":
header_txt = get_header_cell_text(element['table']).lower().strip()
if target_txt.lower() in header_txt:
return element
return None
def get_header_cell_text(table):
""" Given a table element in Google Docs API JSON, find the text of
the first cell in the first row, which should be a column header. """
return table['tableRows'][0]\
['tableCells'][0]\
['content'][0]\
['paragraph']['elements'][0]\
['textRun']['content']
Assuming you've already created a table with the target text in it: now, start by pulling the document JSON object from the API, and then use get_target_table() to find the chunk of JSON related to the table.
doc = build("docs", "v1", credentials=creds).documents().get(documentId=doc_id).execute()
table = get_target_table(doc, "my target")
From there you'll see the nested tableRows and tableCells objects, and the content inside each cell has a startIndex. Construct a matrix of table cell start indices, and then, for populating them, work backwards from the bottom right cell to the upper left, to avoid displacing your stored indices (as suggested in the docs and in one of the comments).
It's definitely a bit of a slog. And styling table cells is a whole 'nother beast, which is a dizzying maze of JSON options. The interactive JSON constructor tool on the Docs API site is useful to get the syntax write.
Hope this helps, good luck!
The answer I arrived at: You can create Docs without using their JSON schema.
https://developers.google.com/drive/api/v3/manage-uploads#node.js_1
So, create the document in your format of choice (HTML, DocX, MD (you'd use pandoc to convert MD to another format)), and then upload that.
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
This question already has answers here:
Google maps saving draggable directions
(2 answers)
Closed 4 years ago.
I want to be able to plot a route in Google Maps, modify that route by dragging it, save the changes and reload it at some later time and edit it further. In the same manner as Google's MyMap. Simply saving the origin and destination locations wont work as it wont reload the same route.
I can save all of the points in the via_waypoint[] array. This allows
me to redraw the route as a polyline but it is no longer editable.
The documentation says that the DirectionsResult is returned in JSON
format. So I've tried to convert the DirectionsResult to a JSON
string, save and reload that string as a JSON object and pass it to
the DirectionsRenderer. But it doesn't display and no errors are
thrown.
Below is a sample of what I was trying to do. I've skipped the saving to the database step. I convert the DirectionsResult to a string and then back to a JSON object.
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var str = JSON.stringify(response))
var obj= JSON.parse(str)
directionsDisplay.setDirections(obj);
}
Any help would be gratefully appreciated.
Thanks
Why not save the coordinates of the waypoint[] array and reintroduce them to the a DirectionsRequest object's waypoints member? Later on, when you reload the page, make a request to the DirectionsService as usual, but with the previously mentioned DirectionsRequest object. It should be draggable if you set draggable to true in the DirectionsRendererOptions of your renderer.