-
Notifications
You must be signed in to change notification settings - Fork 51
/
DataManager.js
135 lines (106 loc) · 5.08 KB
/
DataManager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
Public toilets all over Australia.
Data taken from this data set: https://data.gov.au/dataset/national-public-toilet-map
*/
var DataManager = function () {
var rawData = [];
//function to fake what should happen server side. When returning a large amount of data perform the clustering server
//side to save sending large amounts of data to the client. As the data is just in a js file for this example faking the server side
//clustering using this function. Implement own clustering logic as appropriate, this doesn't do it particularly well.
function fakeServerSideClustering(clusterRatio, maxSingleFlareCount, areaDisplayMode, map) {
var itcount = 0;
console.time("fake-server-side-cluster");
var webExtent = map.extent;
//set up a grid system to do the clustering
//get the total amount of grid spaces based on the height and width of the map (divide it by clusterRatio) - then get the degrees for x and y
var xCount = Math.round(map.width / clusterRatio);
var yCount = Math.round(map.height / clusterRatio);
var xw = (webExtent.xmax - webExtent.xmin) / xCount;
var yh = (webExtent.ymax - webExtent.ymin) / yCount;
var gsxmin, gsxmax, gsymin, gsymax;
var dataLength = rawData.length;
//create an array of clusters that is a grid over the visible extent. Each cluster contains the extent (in web merc) that bounds the grid space for it.
var clusters = [];
for (var i = 0; i < xCount; i++) {
gsxmin = webExtent.xmin + (xw * i);
gsxmax = gsxmin + xw;
for (var j = 0; j < yCount; j++) {
gsymin = webExtent.ymin + (yh * j);
gsymax = gsymin + yh;
var ext = new esri.geometry.Extent({ xmin: gsxmin, xmax: gsxmax, ymin: gsymin, ymax: gsymax });
ext.setSpatialReference(new esri.SpatialReference({ "wkid": 102100 }));
clusters.push({
extent: ext,
clusterCount: 0,
subTypeCounts: [],
singles: [],
points: []
});
}
}
var web, obj;
for (var i = 0; i < dataLength; i++) {
obj = rawData[i];
//get a web merc lng/lat for extent checking. Use web merc as it's flat to cater for longitude pole
web = esri.geometry.lngLatToXY(obj.x, obj.y);
//filter by visible extent first
if (web[0] < webExtent.xmin || web[0] > webExtent.xmax || web[1] < webExtent.ymin || web[1] > webExtent.ymax) {
continue;
}
var foundCluster = false;
//loop cluster grid to see if it should be added to one
for (var j = 0, jLen = clusters.length; j < jLen; j++) {
var cl = clusters[j];
if (web[0] < cl.extent.xmin || web[0] > cl.extent.xmax || web[1] < cl.extent.ymin || web[1] > cl.extent.ymax) {
continue; //not here so carry on
}
//recalc the x and y of the cluster by averaging the points again
cl.x = cl.clusterCount > 0 ? (obj.x + (cl.x * cl.clusterCount)) / (cl.clusterCount + 1) : obj.x;
cl.y = cl.clusterCount > 0 ? (obj.y + (cl.y * cl.clusterCount)) / (cl.clusterCount + 1) : obj.y;
//push every point into the cluster so we have it for area checking if required. This could be omitted if never checking areas, or on demand at least
if (areaDisplayMode) {
cl.points.push([obj.x, obj.y]);
}
cl.clusterCount++;
var subTypeExists = false;
for (var s = 0, sLen = cl.subTypeCounts.length; s < sLen; s++) {
if (cl.subTypeCounts[s].name === obj.facilityType) {
cl.subTypeCounts[s].count++;
subTypeExists = true;
break;
}
}
if (!subTypeExists) {
cl.subTypeCounts.push({ name: obj.facilityType, count: 1 });
}
cl.singles.push(obj);
}
}
var results = [];
//for every cluster that only has one point, just add the actual object to the result
for (var i = 0, len = clusters.length; i < len; i++) {
if (clusters[i].clusterCount === 1) {
results.push(clusters[i].singles[0]);
}
else if (clusters[i].clusterCount > 0) {
if (clusters[i].singles.length > maxSingleFlareCount) {
clusters[i].singles = [];
}
results.push(clusters[i]);
}
}
console.timeEnd("fake-server-side-cluster");
return results;
}
function getData() {
return rawData;
}
function setData(data) {
rawData = data;
}
return {
getData: getData,
setData: setData,
fakeServerSideClustering: fakeServerSideClustering
}
}();