| New file |
| | |
| | | /* |
| | | 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 |
| | | |
| | | } |
| | | |
| | | }(); |
| | | |