In the following example the markers are loaded from a JSON.
If there are 20,000 markers the JSON is going to be quite big.
Is there any way to send different JSON files according to zoom level instead of sending one huge array?
http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/examples/weather_map.html
There's the notion of a "bounding rectangle" for a map view. The map api supplies this to you as two lat/long coordinate pairs - one for the SW corner, and one for the NE corner.
So if you have a custom data service that returns JSON points, you'll need to accept these coordinates as input, and adjust the returned dataset accordingly (most likely as a WHERE clause in your SELECT statement).
I don't have the details of getting this bounding rectangle memorized, but that's what API docs are for.
There is a new library called MarketClustered that will help you
(source: googlecode.com)
Even if the data is too big, I think that will be better to feed the map will all the data, and let it do it's thing.
Yes, I did something similar in an application for a local authority where we were displaying the volume each house recycled across 6,000 odd households. As the total volume of data (which included address and statistical info for each household) was quite large pulling back the whole data file in one go caused the browser to appear to hang.
So instead in the AJAX call to the database we sent the bounding rectangle coordinates (latitude,longitude) of the map area then only returned those points that we visible. Because of the nature of the application a user-driven button to 'fetch data' was quite acceptable, but there's obviously lots of other variations you can play on the theme - once you are delivering the bounding coordinates to the server side you can decide what to do there - for instance only return a subset if the zoom level is too high. You should be able to catch the map draw event too and action this automatically.
When the zoom changes, send the new zoom level to your JSON service and return the markers that should be visible at that level. Use addMarkers() to add the results to MarkerManager and make them visible only at the current zoom level.
The other responses here have suggested returning only the markers within the current view, but you could also just return all of the markers at that zoom level. It depends on how much you know about which markers you want to show at each level.
Possible ways to solve this problem:
Build the JSON on serverside, depending to the zoomlevel (con: needs reload after a zoom, pro: only small amouts of data need to be loaded)
Include the informations about how a marker is accessible in the JSON data (pro: only one time data need to be loaded, con: iterate through the data with JavaScript)
Calculate visible markers in JavaScript (pro: very dynamic, con: heavy calculation load)
Related
I have large files (~100mb each) with GeoJSON/TopoJSON data.
These have states and counties boundaries. States layer loads just fine as it doesn't have so much data, but the one with counties just makes page crash in Chrome.
So, files themselves load from network and are parsed properly, but when it comes to putting them on a Leaflet map, it freezes and crashes.
As a solution, I wonder if I can filter features by their coordinates?
I can get viewport boundaries of the map.
Are there methods I can filter features with coordinates that are inside some boundaries?
This way I could filter only those that should be rendered in the current view and ignore the rest, then repeat this routine on map/zoom.
First of all, Leaflet has a getBounds() method that you can use in order to load only the features that are inside the Bounding Box. This could be done by triggering the getBounds() method when the map "moves" (zoom, dragging), using the moveend event.
So, basically:
map.on('moveend', function() {
map.getBounds()
//erase the features you had on the map
//Then load on the map only the features with coordinates inside the Bounging Box.
}
Of course, the above is just an approach. Every time the map "moves", the previous feautures are erased and new ones are loaded. It may result to slow loading of features but you may have to live with it for so large files.
Also, you can experiment with the code by, for example, loading the new features and then erasing the old. In addition, you can load features for a Box bigger than the Bounding Box.
Is it possible to make a Custom shape (Using Mouse) on the Google Map using Gmap library in C# and then save it into the database and on the client request draw the stored shape on Google Map again? Is there any possibility for doing such operation in any other library or in Gmap (I am not expecting the code. Just an overview of doing it.)?
Oh Boy....this is absolutely doable! And I do it on day to day basis! Let me share how I achieve it. Another thing to keep in mind that this works for Google Maps and Bing Maps.
First, you have to represent Maps as not just coordinates but as collection of small squares. Now what do I mean by that?!
Have a look at this following picture. It's image of Czech Republic on google maps.
Now Czech Republic a.k.a Czechia, on google maps can be seen as collection of smaller square images or grids. You need to understand this concept very well in order to make this idea work. Now take a look at the following image where it shows how the image of Czechia on Google Maps can be visualised as collection of small square boxes or grid. These small square boxes hold images of parts of Czechia.
If you want to Zoom into a co-ordinate Xm,Ym (Easting:Xm, Northing:Ym), which is a place in Czechia and the name of that place is "Hermanuv Mestec" (as shown in the above picture) then you need to choose the bounding small box with co-ordinates (X1,Y1),(X1,Y2),(X2,Y1)&(X2,Y2), and fetch the underlying images in that box. This feature to fetch underlying images within that bounding box is actually Zooming In. So when you Zoom In or in other words fetch the underlying images within that bounding box, you get something as the following image:
Now, I hope you got the underlying concept of how Zoom In or Zoom Out (reverse process) and mapping co-ordinate system works if you want to achieve what you want to achieve because this concept is very important to grasp before you proceed.
You need to write a program which can do this transformation. And as of your question how to achieve this as follows:
Step 1: Use a Panel (Control) on Windows Form or WPF or asp.net application, which you are building.
Step 2: Use GMap Library in C# to fetch the image within a bounding box as mentioned above and populate/draw that image on the Panel.
Step 3: Have a function that tracks mouse events on the panel. This function/method will track the X,Y position of mouse move event on the panel and use Panel Drawing tools to draw objects on the panel based on this.
Step 4: Write another program to transform these mouse X,Y positions on the panel to co-ordidnates on the map. This piece/part of the program is important because this is what enables you to translate your representation of small square image breakdowns of maps into panel drawable objects, so that you can draw them again and again in future if saved properly in the database.
Step 5: When you draw an abject on the panel you track the X,Y mouse bounds on the panel and transform those points into co-rodinates using your custom program and then you save the co-ordinates in the database table.
Thats it! And in case you need to draw the same object saved in the database, you first need to fetch/draw the google maps image on the panel again, then need to fetch that shape of the object from the database by fetching the co-ordinates of that object saved in the database table, use your translation program to convert those co-ordinates into panel drawable points and draw the object back on the same panel.
Now, you can write this translation program (Easting Northing co-ordinates to Drawing Panel co-ordinates) yourself, which might take good few months or at least some time. Or you can buy customised program specialised to achieve this exact same function for a good amount of price.
Hope this helps.
You can also achieve this with Google Maps drawing object with JavaScript as mentioned in another answer but the issue is with the translation and saving the coordinates in the database. It's much faster and responsive in this aforementioned method. Anyway, this is how I do this, so kind of personal opinion.
Technologies required for the aforementioned technique is as follows:
Google Map Library/Bing Map Library (whichever you choose)
C# with .Net Framework 3.5 or above (.net framework lesser than this is also fine but may require bit more lines of code to achieve some functionality if you want to achieve complexity in this)
SQL Server Management Studio or anything equivalent depending on
the type of database and query you are planning to use.
I think you want to make a map overlay, and you can use Goggle Drawing Tools in conjunction with your map. See: https://developers.google.com/maps/documentation/javascript/examples/drawing-tools
This will create the overlay. Presumable you could write javascript code that would save the coordinates and attributes of the overlay to a hidden field once you hit a "Save button" . Then after form submission you could save this info to a database using standard techniques, and then when rendering the map the next time, insert the overlay info into the javascript output by your page,
I am not going to spend the time making this for you, but this is the approach I would take.
steps:
1) Get the geometry/shape out from google api.
2) Send/post to server using some popular exchange format, GeoJSON or WKT
3) Prepare a server's service/asp/web service to accept the request and translate/validate those geometries into Oracle SDO_Geometry user define type/struct.
4) Use some C# oracle library,
a) create Connection,
b) create command with parameter,
c) Initial an OracleObject, assign all the required properties like SDO_GTYPE, SDO_SRID.
d) Assign the OracleObject to the the named parameter in the command.
e) Execute the command and commit.
Hope this help.
Within my application, users can scroll around a Google Map to see various markers and other data that have been placed on the map using the Google Maps API. Whenever the user emits the dragend event, I send a request to my server passing it the current lat/lng of the center of the map, as well as a radius value. My server takes these lat, lng, and radius values and queries the database to see if there are any relevant objects that should be displayed on the map. If there are, they are returned to the browser, and rendered on the map.
I'm trying to avoid making a call to my server every single time the user drags the map. Basically, if the call that would be made would not include any new points, the call should not be made.
I tried to show visually what I mean in the image below:
The filled in blue circles represent areas that have already been queried due to the user positioning the map in the center of each circle. When they do this, a call is made to the server, and data for the area covered by the filled in blue circle is returned.
As they drag around the map, the union of all of these blue areas represents locations for which data has already been retrieved from the server. Now, the small red circle represents a position where if the user were to position the map, I would not want to call the server to load new data. That's because the entire area made up by that center point and radius has already been retrieved; it's already part of the blue area.
On the other hand, the green position represents a location for which I would want to call the server to get data, since some of the area made up by the center point and radius fall outside of the blue area.
I'm wondering if anyone has any approaches for solving this problem. It's got me stumped.
The solution is simple.
1) User drags the thing or whatever.. On the backend, store that location in a session or a database. Load the response as usual.
2) User does whatever again. This time, on the back end check the saved session location from before, calculate the distance between the new position and the one you saved during the last call. You can use Google's API for this. If the distance is smaller than the radius used, you know there will be some overlap and you can filter out those results before returning the data to the front end.
This will reduce the results PHP gives to only the new ones. If you want to avoid making an ajax call alltogether the only way to do that is to load the entire database into javascript. How else would you expect javascript to know if there are any rows.
Could someone suggest the best format to store geolocation coordinates into a websql database? Would it be better to grab the values from an array and store in the format: (52.8165972, -2.1174389000000247),(52.8165972, -2.1174389000000247),(52.8165972, -2.1174389000000247), with each bracket representing a set of coordinates (lat,lng), or would it be better to separate lat and lng values into their own separate columns?
Please bear in mind I will be using the coordinates stored within this database to plot a polyline onto Google maps. The reason I currently have the structure stated above, is because Google maps expects the format of the path values to be (lat, lng).
The current concern is outputting from the database column, all the values in that format, so for example if it's possible to output as (52.8165972, -2.1174389000000247), it may be possible to work with it more easily.
Any advice would be highly appreciated!
EDIT: Additional information about the whole project
I am building an application that is intended to track a users location whilst on walks. The mechanics behind the tracking and drawing a polyline in real-time all work perfectly. Upon "finishing" the walk, the user is taken to a second screen where additional details can be added such as walk titles, descriptions. Information such as the polyline path is output from an array onto the map so that the user can see it. Upon "saving" from this page, all the data is collected both from the arrays for that session and any information entered on that page and stored into its own auto incremental row in the table.
There is another page where the users can view all the walks they have undertaken, this will list out all the individual walk details, and also display a map with that particular walk's polyline added.
You have a range of options.
You could separate them out into individual points (lat/lng pairs) and store each in its own column but this would require you to create as many columns as there are points in your longest polyline. They would be more difficult to query like this.
You could split each pair up into a lat column and a lng column for each point this would be like the previous option but with twice as many columns.
Or you could store the whole polyline in a single column.
I would recommend that last option as it results in a database structure that is more predictable. It is less easy to query to lat/lng data but there are ways around this problem if you can't ignore it.
If you feel the need to query the database by coordinates I suggest you create a few of extra columns that describe a bounding box inside which the polyline fits and/or its centre point.
These would be stored as decimals. See this post for details of the precision you feel is required for your application.
How accurately should I store latitude and longitude?
This will allow you to search for lines or points within a rough area which can be further refined using javascript.
Ever noticed that when you go to maps.google.com and do a search (say, car wash), it renders a lot of results (represented by small circles) and a few prominent ones (seen as regular-size pins)?
Notice how quickly it does this?
From what I can tell from analyzing this in Firebug, much of this is generated on the server and sent to the client as a static image.
However, it's still dynamic. You can still zoom in and out, or click on a result and see a dynamic InfoWindow rendered.
Google have made the map quick and smooth using static images, while still making it flexible.
Is there a way to do this kind of 'pre-loading' with my own Google Map (implemented with the Google Maps API)?
The technology that maps.google.com uses is similar to that used in a GLayer. The server dynamically builds tiles and "hotspot" info. The GLayer tiles are also constructed dynamically (and possibly cached) even though the underlying data is fairly static. From the client side, the searched dots technology is identical to the Wikipedia or Panoramio GLayer. The only new trick is that the dot information is generated dynamically on Google's big fast servers.
The API does not (yet) provide any tools for creating custom GLayers. If you want to do the same sort of thing yourself, using your own database of locations, there are three steps that you need to code:
Create your own custom tileserver
which searches your database for
items in the tile area and uses a
graphics library like gd or
imagemagic to place dots on the
tile. Use those tiles to create a
GTileLayerOverlay on the client.
When the user clicks on the map,
send the location of that click to a
second server. That server should
check your database and return the
infowindow text for the dot at that
location, if any. Returning all the infowindow contents from all the dots imaged by the tileserver would be unacceptably slow, so you have to fetch them one by one, as needed.
Changing the cursor when the mouse
is over a dot is more tricky. What Google
do is return a list of hotspot
coordinates for all the dots on each
tile. Whenever the mouse moves, the
API determines which tile the
pointer is over and uses a quadtree
algorithm to see if the pointer is
over a hotspot, and change the
cursor if necessary. If you only
have a modest number of hotspots per
tile, then a linear search would
probably be acceptably fast. If you might have thousands of dots per tile, then you'll probably need to write your own quadtree algorithm. The Google quadtree code is not exposed, so you can't use it.
Here's a page where somebody has done all that. In this case the hotspots are calculated as circles, by comparing the distance from the centre point, even though the dots are square. On maps.google.com the hotspots are calculated as rectangles, by using GBounds.containsPoint(), even though the dots are round.
I'm doing something similar - but instead using a tile layer, I just send server-clustered markers to the browser whenever the view changes. If your data is static, you can pre-cluster your markers and it would be incredibly fast with tens of thousands of markers.
Our site can't use pre-clustering because the markers can be searched and filtered, but it's still pretty fast up to about 20,000 markers. Still working on it...