I am making a heatmap with Google API v3. I'll give an example. Lets consider earthquake magnitudes. I assign weights to each point to specify their magnitude. However google considers the density of points when you zoom out. The more points are in a place, the redder it gets. For example if two earthqueaks happened within miles of each other, one with magnitude 3 and another with magnitude 8, the first one should be green/blue and the 2nd one would be red. But once you zoom out and the two points get closer in the map, google maps considers the number of points instead of the weights and as a result, it appears read. I want it to be the average i.e. (3+8)/2=5.5...whatever color that represents. Is this possible?
There is a somewhat decent workaround if you are like me and don't have the processing time or power to generate an overlay and you can't modify any existing libraries to your liking.
I used the google maps heatmap library and set maxIntensity and dissipating to false. Setting the maxIntensity to a value of your choosing will solve the problem of your heatmap-points getting colored in relation to eachother instead of to 0 or a set value. Setting dissipating to false will disable the automatic radius settings that happen when you change zoom levels.
Next I made an event for every time the zoom level changed and in that event I set the radius to a value that seemed to represent my data in the most accurate way for that zoom level.
Now to get rid of the problem where datapoints on the map blend and get added together into a big red blob, I decided to make a seperate grid on my map for every zoom level I want to use. I average all the values that are boxed inside the same grid point and make sure that the grid is large enough to keep heatmap points from overlapping, but small enough to not look like a bunch of circles. (I found that the grid should be about 0.4 times the size of the heatpoint radius on the map for smooth looks).
The radius of the heatmap point is set by google in pixels. I didn't know how to convert pixels to Lat/Long so I just measured it by drawing lines past a circle with a certain radius and measured the distance between these lines. That conversion method will work pretty well if you aren't planning on mapping much more than a small country.
Performance wise this isn't as bad as I thought it would be. I'm loading about 2300 points and the map loads as fast as it did before I made a grid for every zoom level, and you don't actually see the data points being refreshed as you change zoom levels.
Here are some pieces of code for all of the above:
Map settings:
map.heatmap.set('maxIntensity', 12000);
map.heatmap.set('dissipating', false);
Change grid and radius per zoom level:
map._on({
obj: map.gMap,
event: "zoom_changed",
callback: function(){
var zoomLevel = map.zoom();
switch(zoomLevel){
case 7:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.04);
break;
case 8:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.03);
break;
case 9:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.02);
break;
case 10:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.01);
break;
case 11:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.005);
break;
case 12:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.0025);
break;
case 13:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.00225);
break;
default:
map.heatmap.setData(gridData[zoomLevel]);
map.heatmap.set('radius', 0.000625);
}
}
});
My grids are generated in PHP which will probably look different for everyone, but just as an example, here's the function I use:
function getHeatGrid($gridSize){
$mapGrid = false;
$mapData = false;
$radius = $gridSize * 2.8 * 0.3; //grid size is multiplied by 2.8 to convert from the heat map radius to lat/long values(works for my lat/long, maybe not yours). * 0.3 is arbitrary to avoid seeing the grid on the map.
$string = file_get_contents("mapData.json");
$json_a = json_decode($string, true);
forEach($json_a as $key => $value){
$row = intval(round(($value['center_longitude'] / $radius)));
$column = intval(round(($value['center_latitude'] / $radius)/68*111)); //around 52.0;5.0 latitude needs to be scaled to make a square grid with the used longitude grid size
if(isset($mapGrid[$row][$column])){
$mapGrid[$row][$column] = round(($value['solarValue'] + $mapGrid[$row][$column]) / 2);
} else {
$mapGrid[$row][$column] = $value['solarValue'];
}
}
forEach($mapGrid as $long => $array){
forEach($array as $lat => $weight){
$mapData[] = array(
"center_longitude" => $long * $radius,
"center_latitude" => ($lat * $radius)/111*68,
"solarValue" => $weight
);
}
}
return $mapData;
}
Unfortunately I can't display the map right now as it is currently kept private for clients of the company that I work at, but if it becomes available publically I will add a link so you can see how well this method works.
Hope this helps someone.
Lukas
You can do it by overlaying a heatmap image on top of the map. There's a very good open source example at https://github.com/jeffkaufman/apartment_prices
A heatmap by definition considers point density as well as the weight assigned to each point. At least Google's heat map work this way as far as I know from working with them. So what you actually need is not a heatmap but a map of points that they will be coloured depending on a value.
I also needed to change the ratio density/weight that Google heatmaps take into consideration in order to colour the map but i didn't find any way. Currently the heatmap's main factor is the density and a change in weight has small effect on the colour.
As a partial solution, I've modified heatmap.js from the following project: https://github.com/pa7/heatmap.js
To get an average at a single long/lat point I've modified the _organiseData function to store the PointCount and PointSum for each x,y position; and with these values I get the average at a point with:
store[x][y] = storePointSum[x][y] / storePointCount[x][y];
I'm still working out how to modify the "blend" when multiple x,y coords stack at various map resolutions... If I figure it out I will post it.
cheers
~Aaron
This example uses heatmaps as a layer over the map, hope it helps : http://maps.forum.nu/v3/gm_customTiles.html
© 2022 - 2024 — McMap. All rights reserved.