1 2var GITBRANCH = 'stable'; // metadata and source data is read from this branch 3 4function getZipFileContent(zipdata, name) { 5 console.log('unzipping...'); 6 var zip = new JSZip(zipdata); 7 var topodata = zip.file(name).asText(); 8 console.log('unzipped '+name); //+' '+topodata.substring(0,1000)); 9 return topodata; 10}; 11 12function Topoj2Geoj(topoj) { 13 function transformArcs(arcs, scale, translate) { 14 for (let i = 0, ii = arcs.length; i < ii; ++i) { 15 transformArc(arcs[i], scale, translate); 16 } 17 }; 18 function transformArc(arc, scale, translate) { 19 let x = 0; 20 let y = 0; 21 for (let i = 0, ii = arc.length; i < ii; ++i) { 22 const vertex = arc[i]; 23 x += vertex[0]; 24 y += vertex[1]; 25 vertex[0] = x; 26 vertex[1] = y; 27 transformVertex(vertex, scale, translate); 28 } 29 }; 30 function transformVertex(vertex, scale, translate) { 31 vertex[0] = vertex[0] * scale[0] + translate[0]; 32 vertex[1] = vertex[1] * scale[1] + translate[1]; 33 }; 34 function concatenateArcs(indices, arcs) { 35 const coordinates = []; 36 let index, arc; 37 for (let i = 0, ii = indices.length; i < ii; ++i) { 38 index = indices[i]; 39 if (i > 0) { 40 // splicing together arcs, discard last point 41 coordinates.pop(); 42 } 43 if (index >= 0) { 44 // forward arc 45 arc = arcs[index]; 46 } else { 47 // reverse arc 48 arc = arcs[~index].slice().reverse(); 49 } 50 // THIS IS THE FIX 51 //coordinates.push.apply(coordinates, arc); 52 for (p of arc) { 53 coordinates.push(p); 54 }; 55 } 56 // provide fresh copies of coordinate arrays 57 /* 58 for (let j = 0, jj = coordinates.length; j < jj; ++j) { 59 coordinates[j] = coordinates[j].slice(); 60 } 61 */ 62 return coordinates; 63 }; 64 function readPolygonGeometry(object, arcs) { 65 const coordinates = []; 66 for (let i = 0, ii = object['arcs'].length; i < ii; ++i) { 67 coordinates[i] = concatenateArcs(object['arcs'][i], arcs); 68 } 69 return coordinates; //new Polygon(coordinates); 70 }; 71 function readMultiPolygonGeometry(object, arcs) { 72 const coordinates = []; 73 for (let i = 0, ii = object['arcs'].length; i < ii; ++i) { 74 // for each polygon 75 const polyArray = object['arcs'][i]; 76 const ringCoords = []; 77 for (let j = 0, jj = polyArray.length; j < jj; ++j) { 78 // for each ring 79 ringCoords[j] = concatenateArcs(polyArray[j], arcs); 80 } 81 coordinates[i] = ringCoords; 82 } 83 return coordinates; //new MultiPolygon(coordinates); 84 }; 85 const GEOMETRY_READERS = { 86 //'Point': readPointGeometry, 87 //'LineString': readLineStringGeometry, 88 'Polygon': readPolygonGeometry, 89 //'MultiPoint': readMultiPointGeometry, 90 //'MultiLineString': readMultiLineStringGeometry, 91 'MultiPolygon': readMultiPolygonGeometry, 92 }; 93 // transform quantized coordinates 94 var transform = topoj['transform'] 95 if (transform) { 96 scale = transform['scale']; 97 translate = transform['translate']; 98 transformArcs(topoj['arcs'], scale, translate); 99 }; 100 // make geojson 101 var layers = Object.keys(topoj.objects); 102 var lyr = layers[0]; 103 var features = []; 104 for (obj of topoj.objects[lyr].geometries) { 105 var reader = GEOMETRY_READERS[obj.type]; 106 var coords = reader(obj, topoj.arcs); 107 var geom = {'type':obj.type, 'coordinates':coords}; 108 var feat = {'type':'Feature', 109 'geometry':geom, 110 'properties':obj.properties}; 111 //console.log(feat); 112 features.push(feat); 113 }; 114 var geoj = {'type':'FeatureCollection', 115 'features':features}; 116 return geoj; 117}; 118 119/* 120function fixTopoJSON(topoj) { 121 console.log('truncating...'); 122 for (i=0; i<topoj.arcs.length; i++) { 123 // truncate to first 100,000 points 124 arc = topoj.arcs[i]; 125 if (arc.length > 100*1000) { 126 var newArc = arc.slice(0, 100*1000); 127 // add the last point 128 var lastpoint = arc[arc.length-1]; 129 newArc.push(lastpoint); 130 topoj.arcs[i] = newArc; 131 }; 132 //console.log(topoj.arcs[i].length); 133 }; 134 console.log('done truncating'); 135}; 136*/ 137 138function loadFromTopoJSON(source, topoj) { 139 //alert('reading features...'); 140 141 // TEMPORARY: 142 // manually convert to geojson and redirect to geojson loading 143 // fixes call stack error inherent in ol.format.TopoJSON reader 144 console.log('topoj 2 geoj...') 145 var geoj = Topoj2Geoj(topoj); 146 console.log('geoj loaded'); 147 // redirect to geojson loader 148 loadFromGeoJSON(source, geoj); 149 // exit early 150 return 151 152 // standard openlayers approach 153 var format = new ol.format.TopoJSON({}); 154 155 // debug explore arc lengths as a cause of maximum call stack error 156 //console.log('topo objects '+topoj.objects.data.geometries.length) 157 //console.log('topo arcs '+topoj.arcs.length) 158 /* 159 var layers = Object.keys(topoj.objects); 160 var lyr = layers[0]; 161 for (geom of topoj.objects[lyr].geometries) { 162 var polys = geom.arcs; 163 if (geom.type == 'Polygon') { 164 polys = [geom.arcs] 165 }; 166 //console.log(polys) 167 var coords = []; 168 var count = 0;
169 for (poly of polys) { 170 for (ring of poly) { 171 for (i of ring) { 172 i = Math.abs(i); 173 arc = topoj.arcs[i]; 174 //console.log('arc '+i+' of '+topoj.arcs.length) 175 console.log(coords.length+' + '+arc.length) 176 coords.push.apply(coords, arc); 177 count += arc.length; 178 }; 179 }; 180 }; 181 console.log('obj point count '+count) 182 }; 183 */ 184 //console.log('topo arc1 '+topoj.arcs[0].length) 185 //console.log('topo obj1 '+JSON.stringify(topoj.objects.data.geometries[0])) 186 //console.log('topo obj1 arcs '+topoj.objects.data.geometries[0].arcs.length) 187 //console.log('topo obj1 total points '+count) 188 189 // read the features 190 //console.log('loading features...') 191 var features = format.readFeatures(topoj, { 192 dataProjection: 'EPSG:4326', 193 featureProjection: 'EPSG:3857' 194 } 195 ); 196 //console.log('features loaded'); 197 // set ids 198 var i = 1; 199 for (feat of features) { 200 feat.setId(i); 201 i++; 202 }; 203 // add 204 //console.log('adding features...'); 205 source.addFeatures(features); 206 //console.log('features added'); 207}; 208 209function loadFromGeoJSON(source, geoj) { 210 //alert('reading features...'); 211 var format = new ol.format.GeoJSON({}); 212 var allFeatures = format.readFeatures(geoj, { 213 dataProjection: 'EPSG:4326', 214 featureProjection: 'EPSG:3857' 215 } 216 ); 217 //alert(features.length + ' features fetched'); 218 // set ids 219 var i = 1; 220 var features = []; 221 for (feat of allFeatures) { 222 if (feat.getGeometry() == null) { 223 // ignore null geoms 224 continue; 225 }; 226 features.push(feat); 227 feat.setId(i); 228 i++; 229 }; 230 // add 231 source.addFeatures(features); 232 //alert('features added'); 233}; 234 235function loadGeoContrastSource(source, iso, level, sourceName) { 236 // get geoContrast metadata 237 var metadata = geoContrastMetadata; 238 // find the data url from the corresponding entry in the meta table 239 for (var i = 1; i < metadata.length; i++) { 240 var row = metadata[i]; 241 if (row.length <= 1) { 242 // ignore empty rows 243 i++; 244 continue; 245 }; 246 var currentIso = row.boundaryISO; 247 var currentLevel = row.boundaryType; 248 var currentSource = row['boundarySource-1']; 249 if ((sourceName == currentSource) & (iso == currentIso) & (level == currentLevel)) { 250 // get the data url from the table entry 251 var apiUrl = row.apiURL; 252 break; 253 }; 254 }; 255 // manually load topojson from url 256 if (apiUrl.endsWith('.topojson')) { 257 fetch(apiUrl) 258 .then(resp => resp.json()) 259 .then(out => loadFromTopoJSON(source, out)) 260 //.catch(err => alert('Failed to load data from '+apiUrl+'. Please choose another source. Error: '+JSON.stringify(err))); 261 } else if (apiUrl.endsWith('.zip')) { 262 if (GITBRANCH != 'stable') { 263 // HACKY FIX: 264 // all metadata api urls are set to stable 265 // until this is changed, hacky replace with branch name for now 266 apiUrl = apiUrl.replace('/geoContrast/stable/', '/geoContrast/'+GITBRANCH+'/'); 267 }; 268 var splitUrl = apiUrl.split('/'); 269 var extractName = splitUrl[splitUrl.length-1].replace('.zip',''); 270 if (extractName.endsWith('.topojson')) { 271 /* 272 JSZipUtils.getBinaryContent(apiUrl, function(err, data) { 273 console.log(err); 274 console.log(data); 275 topoj = JSON.parse(getZipFileContent(data, extractName)); 276 loadFromTopoJSON(source, topoj); 277 }) 278 */ 279 fetch(apiUrl) 280 .then(resp => resp.arrayBuffer() ) 281 .then(out => loadFromTopoJSON( source, JSON.parse(getZipFileContent(out, extractName))) ) 282 //.catch(err => alert('Failed to load data from '+apiUrl+'. Please choose another source. Error: '+JSON.stringify(err))); 283 }; 284 }; 285}; 286 287function loadGeoContrastMetadata(onSuccess) { 288 // fetch metadata 289 // determine url of metadata csv 290 url = 'https://raw.githubusercontent.com/wmgeolab/geoContrast/18c5aff53ae64b38803b01786da78b63344c5809/releaseData/geoContrast-meta.csv'; 291 if (GITBRANCH != 'stable') { 292 // HACKY FIX: 293 // all metadata api urls are set to stable 294 // until this is changed, hacky replace with branch name for now 295 url = url.replace('/geoContrast/stable/', '/geoContrast/'+GITBRANCH+'/'); 296 }; 297 // define error and success 298 function error (err, file, inputElem, reason) { 299 alert('geoContrast metadata csv failed to load: '+url); 300 }; 301 function success (result) { 302 //alert('load success'); 303 // process csv data using custom function 304 onSuccess(result['data']); 305 }; 306 // parse 307 Papa.parse(url, 308 {'download':true, 309 'header':true, 310 'complete':success, 311 'error':error, 312 } 313 ); 314}; 315
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.