Reputation: 2086
I have a list of customers with some sales data and their coordinates. I would like to display it on a map, but rather than having 10,000 markers I would like to group them to get circles of varying radius depending on the number of customers in the area. Here is a sample of my data set:
[
{
"latitude": "44.141638",
"longitude": "-149.935598",
"family_size": 1
},
{
"latitude": "44.141314",
"longitude": "-149.935556",
"family_size": 3
},
{
"latitude": "44.200873",
"longitude": "-130.025254",
"family_size": 2
},
{
"latitude": "45.202873",
"longitude": "-131.0243 54",
"family_size": 2
}
]
My thought was to take the latitude and longitude from each record and using a slider / zoom level combo adjust the number of decimal points so that as you zoom out, you would see them in groups. So for example, as you zoom out the first 2 records would convert to:
{
"latitude": "44.141",
"longitude": "-149.935",
"family_size": 3
},
{
"latitude": "44.141",
"longitude": "-149.935",
"family_size": 1
}
Then I would define the radius as the count of family members at matching coordinates, so this would be a total of 4.
I have seen a way to get the count of unique values in an array, but how do you get a count when you need to match 2 key/value pairs?
The incoming data has about 10,000 records, I was hoping to load the data to the browser and let the client PC handle the workload rather than trying to do it all in PHP / AJAX because I want them to be able to manipulate what is displayed by dates, genders, revenue...
I have a method that is working on a small scale, but fails in 2 ways when scaled up to many records. First is that the counter for some reason gets off by a lot, second as I feared looping in this way is very inefficient.
Here is what I have:
function GroupXY(arr) {
var a = [],b = [],prev;
arr.sort();
for (var i = 0; i < arr.length; i++) {
if (arr[i].latitude !== prev) {
a.push(arr[i]);
}
prev = arr[i].latitude;
}
var c = [], d = [], prevL;
for (var L = 0; L < arr.length; L++) {
if (arr[L].longitude !== prevL) {
c.push(arr[L]);
}
prevL = arr[L].longitude;
}
var matches = {},
counter = [];
for (var M = 0; M < arr.length; M++) {
for (var A = 0; A < a.length; A++) {
if (isEmpty(matches[a[A].latitude])) {
matches[a[A].latitude] = {};
}
var uniqueLatitude = a[A].latitude;
if (arr[M].latitude == uniqueLatitude) {
for (var C = 0; C < c.length; C++) {
var thisLongitude = c[C].longitude;
if (arr[M].longitude === thisLongitude && arr[M].latitude == c[C].latitude) {
//Full Match
if (isEmpty(matches[uniqueLatitude])) {
matches[uniqueLatitude][thisLongitude] = arr[M].family_size;
} else {
matches[uniqueLatitude][thisLongitude] = matches[uniqueLatitude][thisLongitude] + arr[M].family_size;
}
} else {
}
}
} else {}
}
}
}
Here is a jsfiddle of it with data: https://jsfiddle.net/xpvt214o/450422/
While it did well on 5 records at a time, when I tried to feed it 5000 records, it completely froze the browser and started giving crazy family_size results like 40,000.
Seems like grouping XY coordinates would be something javascript would excel at and have something built in so it could be handled in compiled code instead of scripting.
Upvotes: 0
Views: 618
Reputation: 2086
After rewriting it a few times, because of speed issues, this is what I came up with. Because of the number of records I had, I felt filtering them once to get unique latitudes would be helpful.
function filterArray(incomingArray){
var unique = {};
var distinct = [];
for( var i in incomingArray ){
if( typeof(unique[incomingArray[i][0]]) == "undefined"){
distinct.push([incomingArray[i][0],{}]);
}
unique[incomingArray[i][0]] = 0;
}
return distinct;
}
function GroupCoords(incomingArray, rounding) {
var xy = [];
for(var i =0; i<incomingArray.length; i++){
var latitude = parseFloat(incomingArray[i].latitude).toFixed(rounding);
xy.push([latitude]);
}
var locations =filterArray(xy);
for(var i =0; i<incomingArray.length; i++){
var latitude = parseFloat(incomingArray[i].latitude).toFixed(rounding);
var longitude = parseFloat(incomingArray[i].longitude).toFixed(rounding);
var familySize = incomingArray[i].family_size;
for(var X =0; X<locations.length; X++){
if(latitude==locations[X][0]){
if(!locations[X][longitude]){
locations[X][longitude]=familySize;
counter = counter + familySize;
}else{
locations[X][longitude] = locations[X][longitude] + familySize;
counter = counter + familySize;
}
}
}
}
return locations;
}
console.log(GroupCoords(data, 3));
Would return an array such as:
[
[
"30.557", //latitude
{
"-87.260": 1 // longitude : family_size
}
],
[
"30.570",//latitude
{
"-87.260": 1 // longitude : family_size
},
{
"-87.340": 4 // longitude : family_size
}
]
]
Each latitude can have multiple longitudes which can contain any extra info you want to store. by rounding the coordinates to 3 it reduced about 6000 records to about 750 almost instantly which will allow me to use a slider to adjust the grouping size.
Upvotes: 0
Reputation: 1549
See this:- After Maps initialize and the array of markers call this
see this Example With Whole Code
var markerCluster = new MarkerClusterer(map, markers,
{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
}
Upvotes: 1