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...
Related
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.
So, basic gist is, I have my own tiles of not the real world I'd like to display with the Google Maps viewer. I've found examples of how to split an existing single image into tiles for use with it, but nothing that deals with setting up your own tiler.
I have map data such as this:
https://dl.dropboxusercontent.com/u/44766482/superimage/index.html
Which right now is just a bunch of 1600x1600 images in an html table. This naive method works, but I'd like to switch to the more robust google api for better zooming and smarter streaming of the image data.
I've been unable to find a good example of how to generate your own tiles for the zoom levels and bring it together with some html/js.
If you want some more information for the goal process;
I have a python script that can output any size tiles of the map, at any zoom level. I'd like to bundle those together into a google maps api website. But in my own efforts I have not found a good example or documentation of how to do that. For one, I can only find examples of how the zoom levels work for the real world map, but not for a custom one.
Edit:
Got most things working as I want them, but I'm still confused regarding the "center" that can be set, as it's in lat and lng, which don't apply. I'd also like to set boundaries as currently it tries to load .png files outside of the maps range.
My current progress:
https://dl.dropboxusercontent.com/u/44766482/googlemapspreview/index.html
I think what you are looking for is the google maps imageMapTypes:
https://developers.google.com/maps/documentation/javascript/maptypes#ImageMapTypes
Basically, each zoom level is the 4 lower zoom tiles combined. A Projection function can be skipped to get orthogonal mapping.
I am currently working on a map generator application based on javascript, and I have wrote more than 400 lines of code, that creates a hexagonal map, adds coordinates to tiles, adds textures on tiles like grass, ocean and elements like castles, units etc.
I have added quite a few useful functions to this offline map editor, like zoom in and zoom out, turning grid on/off, dragging the map, and a few others, and I'm currently studying on how to add save and load functionality to this offline game map editor.
It sort of looks like a paint application, except that instated of drawing pixels, you use it to draw a map with hex tiles. You simply click on Generate a new map and you give your desired map size (e.g 64 tiles width by 64 tiles height) and the map is drawn for you, the tiles are simple divs that have the relative background image as texture. Tiles are drawn one by one using a simple for loop. But as the code grows in size so does my worries.
Because the map I create on my own map editor will be used on an online multiplayer game, it will be huge! for example to support at least 20000 users on the upcoming game there should be at least 20000 tiles, only for the users to occupy, not to mention the territory they will own, mountains, jungles, barbarian tribes, and so on..
I have made the calculations and found out that a 512 by 512 (about 262000 tiles) map will sufficiently answer the needs of that many users. However, the map will be huge. so I decided to test and see how much load time does it take to make such a map using the codes I have created with the least process possible and I found out that it takes nearly a minute or more, which is not acceptable, from a gamers perspective.
A zoom in for example in such a huge map will mean looping through every 262000 tile to change their size. although the process takes less time than drawing/loading the map from scratch, but it is still slow.
I was thinking with a map that huge which won't even fit in a browser's window, why should I draw the entire map? why not instead load the part which the user is currently looking at. Loading/drawing only the part that is needed, this way reducing load time and increasing performance. But this is proving to be a real challenge, and there are very limited resources online about implementing such a functionality. Where to start? How to approach the problem and respective solution?
I would start out by separating your concerns a little more. You're able to view WxH number of pixels, and the top left of the user's screen sits at (x,y) coordinates.
Loading the entire map, as you have pointed out, is crazy. But by knowing how large the game world is, and by knowing the user's coordinates in that world, you can easily select the subset of items that are in view.
Keep in mind that at a zoomed out resolution you shouldn't be using the full-sized images. Loading 262000 images (for just the map!) is going to be too heavy and probably crash. You should have different images for different zoom levels. This is a much bigger question and you should buy a book and do more research on google. But at least the thinking about the "where the user is" vs "where the items in the world are" is a place that I would start at.
Hope that helps.
I'm trying to show website usage statistics in a more graspable way. I'd like to use google maps API to have dots flash in random areas of a country every time someone in that country logs in.
My question is two part.
Firstly, is there a built in way to create a dot on google maps without using overlays, or with an overlay that will delete itself after a given period of time (say 25ms)?
Second, is there a way to generate random coordinates that will be used to generate the dot? The difficulty that I'm having is that I need to make sure it stays within the country that the user logged in and it needs to be in a plausible location. It'll be pretty obvious that it's a made up location if it continually shows usage in the water.
I could create a file with millions of coordinates for each country and have it randomly draw from that file, but I'm trying to avoid that.
Thanks in advance
interesting use case:)
"is there a built in way to create a dot on google maps without using overlays, or with an overlay that will delete itself after a given period of time (say 25ms)?"
I recommend just creating the overlay and using jquery (or whatever framework you use) to do a nice animate to slowly hide the overlay. Once hidden you can remove it ($(".theelementselector').remove())
As to your second question:
Lot's of ways to go about this, one of the best imho would be:
get your hands on polygon data of countries (tip: www.weogeo.com for free downloads on request)
given a boundingbox of the country
generate a random point in the bounding box (for instance with the so called "monte carlo method.")
check if it's in the polygon as well (point polygon intersect. Look it up on SO for example)
hth
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)