Esempio n. 1
0
    sampleAccurateHeight(terrainProvider, position) {
        if (this.tileRequestInFlight) {
            // A tile request is already in flight, so reschedule for later.
            this.debounceSampleAccurateHeight.cancel();
            this.debounceSampleAccurateHeight(terrainProvider, position);
            return;
        }

        const positionWithHeight = Cartographic.clone(position);

        const geoidHeightPromise = this.geoidModel ? this.geoidModel.getHeight(position.longitude, position.latitude) : undefined;
        const terrainPromise = sampleTerrainMostDetailed(terrainProvider, [positionWithHeight]);
        this.tileRequestInFlight = when.all([geoidHeightPromise, terrainPromise], result => {
            const geoidHeight = result[0] || 0.0;
            this.tileRequestInFlight = undefined;
            if (Cartographic.equals(position, this.lastHeightSamplePosition)) {
                position.height = positionWithHeight.height - geoidHeight;
                this.cartographicToFields(position);
            } else {
                // Mouse moved since we started this request, so the result isn't useful.  Try again next time.
            }
        }, () => {
            this.tileRequestInFlight = undefined;
        });
    }
Esempio n. 2
0
CatalogGroup.updateItems = function(itemsJson, options, catalogGroup) {
    if (!(itemsJson instanceof Array)) {
        throw new DeveloperError('JSON catalog description must be an array of groups.');
    }

    options = defaultValue(options, defaultValue.EMPTY_OBJECT);
    var onlyUpdateExistingItems = defaultValue(options.onlyUpdateExistingItems, false);

    var promises = [];

    for (var itemIndex = 0; itemIndex < itemsJson.length; ++itemIndex) {
        var itemJson = itemsJson[itemIndex];

        if (!defined(itemJson.name) && !defined(itemJson.id)) {
            throw new RuntimeError('A catalog member must have a name or a id for matching.');
        }

        var itemObject;
        if (itemJson.id) {
            itemObject = catalogGroup.terria.catalog.shareKeyIndex[itemJson.id];
        } else if (itemJson.name) {
            itemObject = catalogGroup.findFirstItemByName(itemJson.name);
        }

        var updating = defined(itemObject);

        if (!updating) {
            // Skip this item entirely if we're not allowed to create it.
            if (onlyUpdateExistingItems) {
                continue;
            }

            if (!defined(itemJson.name)) {
                throw new RuntimeError('A newly created catalog member must have a name.');
            }

            if (!defined(itemJson.type)) {
                throw new RuntimeError('A catalog member must have a type.');
            }

            itemObject = createCatalogMemberFromType(itemJson.type, catalogGroup.terria);
        }

        promises.push(itemObject.updateFromJson(itemJson, options));

        if (!updating) {
            catalogGroup.add(itemObject);
        }
    }

    catalogGroup.sortItems();

    return when.all(promises);
};
    return promise.then(function(token) {
      that._lastToken = token;

      var serviceUri = getBaseURI(that);
      var layersUri = getBaseURI(that).segment(layers); // either 'layers' or a number
      var legendUri = getBaseURI(that).segment("legend");

      if (token) {
        serviceUri.addQuery("token", token);
        layersUri.addQuery("token", token);
        legendUri.addQuery("token", token);
      }

      var serviceMetadata = that._mapServerData || getJson(that, serviceUri);
      var layersMetadata = that._layersData || getJson(that, layersUri);
      var legendMetadata = that._legendData || getJson(that, legendUri);

      return when
        .all([serviceMetadata, layersMetadata, legendMetadata])
        .then(function(results) {
          if (defined(results[1].layers)) {
            that.updateFromMetadata(results[0], results[1], results[2], false);
          } else if (defined(results[1].id)) {
            // Results of a single layer query. Make it look like a multi layer query result.
            that.updateFromMetadata(
              results[0],
              { layers: [results[1]] },
              results[2],
              false,
              results[1]
            );
          } else {
            var message = defined(results[0].error)
              ? results[0].error.message
              : "This dataset returned unusable metadata.";
            throw new TerriaError({
              title: "ArcGIS Mapserver Error",
              message:
                "<p>" +
                message +
                '</p><p>Please report it by \
sending an email to <a href="mailto:' +
                that.terria.supportEmail +
                '">' +
                that.terria.supportEmail +
                "</a>.</p>"
            });
          }
        });
    });
ArcGisMapServerCatalogItem.prototype.loadLegendFromJson = function(json) {
  var options = { title: "" };
  var layers = !defined(this.layers)
    ? []
    : this.layers.toLowerCase().split(",");
  var itemPromises = [];
  var shownLegends = {};
  json.layers.forEach(function(l) {
    if (noDataRegex.test(l.layerName) || labelsRegex.test(l.layerName)) {
      return;
    }
    if (
      defined(this.layers) &&
      layers.indexOf(String(l.layerId)) < 0 &&
      layers.indexOf(l.layerName.toLowerCase()) < 0
    ) {
      return;
    }
    options.title = replaceUnderscores(l.layerName);
    l.legend.forEach(function(leg) {
      if (shownLegends[leg.label + leg.imageData]) {
        // Hide truly duplicate layers.
        return;
      }
      shownLegends[leg.label + leg.imageData] = true;
      var title = leg.label !== "" ? leg.label : l.layerName;
      itemPromises.push(
        loadImage(
          replaceUnderscores(title),
          "data:" + leg.contentType + ";base64," + leg.imageData
        )
      );
    }, this);
  }, this);
  var that = this;
  if (itemPromises.length === 0) {
    return;
  }
  return when
    .all(itemPromises)
    .then(function(items) {
      items.reverse();
      options.items = items;
      return (that._generatedLegendUrl = new Legend(options).getLegendUrl());
    })
    .otherwise(function(error) {
      throw error;
    });
};
WebMapServiceCatalogItem.prototype._load = function() {
    var that = this;
    var promises = [];

    if (!defined(this._rawMetadata)) {
        promises.push(loadXML(proxyCatalogItemUrl(this, this.getCapabilitiesUrl)).then(function(xml) {
            var metadata = capabilitiesXmlToJson(xml);
            that.updateFromCapabilities(metadata, false);
        }));
    }

    // Query WMS for wfs or wcs URL if no dataUrl is present
    if (!defined(this.dataUrl)) {
        var describeLayersURL = cleanUrl(this.url) + '?service=WMS&version=1.1.1&sld_version=1.1.0&request=DescribeLayer&layers=' + encodeURIComponent(this.layers);

        promises.push(loadXML(proxyCatalogItemUrl(this, describeLayersURL)).then(function(xml) {
            var json = xml2json(xml);
            // LayerDescription could be an array. If so, only use the first element
            var LayerDescription = (json.LayerDescription instanceof Array) ? json.LayerDescription[0] : json.LayerDescription;
            if (defined(LayerDescription) && defined(LayerDescription.owsURL) && defined(LayerDescription.owsType)) {
                switch (LayerDescription.owsType.toLowerCase()) {
                    case 'wfs':
                        if (defined(LayerDescription.Query) && defined(LayerDescription.Query.typeName)) {
                            that.dataUrl = cleanUrl(LayerDescription.owsURL) + '?service=WFS&version=1.1.0&request=GetFeature&typeName=' + LayerDescription.Query.typeName + '&srsName=EPSG%3A4326&maxFeatures=1000';
                            that.dataUrlType = 'wfs-complete';
                        }
                        else {
                            that.dataUrl = cleanUrl(LayerDescription.owsURL);
                            that.dataUrlType = 'wfs';
                        }
                        break;
                    case 'wcs':
                        if (defined(LayerDescription.Query) && defined(LayerDescription.Query.typeName)) {
                            that.dataUrl = cleanUrl(LayerDescription.owsURL) + '?service=WCS&version=1.1.1&request=DescribeCoverage&identifiers=' + LayerDescription.Query.typeName;
                            that.dataUrlType = 'wcs-complete';
                        }
                        else {
                            that.dataUrl = cleanUrl(LayerDescription.owsURL);
                            that.dataUrlType = 'wcs';
                        }
                        break;
                }
            }
        }).otherwise(function(err) { })); // Catch potential XML error - doesn't matter if URL can't be retrieved
    }

    return when.all(promises);
};
Esempio n. 6
0
/**
 * Returns a promise which, when resolved, indicates that item._conceptIds and item._conceptNamesMap are loaded.
 * @private
 * @param  {AbsIttCatalogItem} item This catalog item.
 * @return {Promise} Promise which, when resolved, indicates that item._conceptIds and item._conceptNamesMap are loaded.
 */
function loadConceptIdsAndConceptNameMap(item) {
  if (!defined(item._loadConceptIdsAndNameMapPromise)) {
    var parameters = {
      method: "GetDatasetConcepts",
      datasetid: item.datasetId,
      format: "json"
    };
    var datasetConceptsUrl = item._baseUrl + "?" + objectToQuery(parameters);
    var loadDatasetConceptsPromise = loadJson(datasetConceptsUrl)
      .then(function(json) {
        item._conceptIds = json.concepts;
        if (
          json.concepts.indexOf(item.regionConcept) === -1 ||
          json.concepts.indexOf("REGIONTYPE") === -1
        ) {
          throw new DeveloperError(
            "datasetId " +
              item.datasetId +
              " concepts [" +
              json.concepts.join(", ") +
              '] do not include "' +
              item.regionConcept +
              '" and "REGIONTYPE".'
          );
        }
      })
      .otherwise(throwLoadError.bind(null, item, "GetDatasetConcepts"));
    var loadConceptNamesPromise = loadJson(item.conceptNamesUrl).then(function(
      json
    ) {
      item._conceptNamesMap = json;
    });

    item._loadConceptIdsAndNameMapPromise = when.all([
      loadConceptNamesPromise,
      loadDatasetConceptsPromise
    ]);
    // item.concepts and item.conceptNameMap are now defined with the results.
  }
  return item._loadConceptIdsAndNameMapPromise;
}
Esempio n. 7
0
// Loads region ids from the region providers, and returns the region details.
function loadRegionIds(regionMapping, rawRegionDetails) {
  var promises = rawRegionDetails.map(function(rawRegionDetail) {
    return rawRegionDetail.regionProvider.loadRegionIDs();
  });
  return when
    .all(promises)
    .then(function() {
      // Cache the details in a nicer format, storing the actual columns rather than just the column names.
      regionMapping._regionDetails = rawRegionDetails.map(function(
        rawRegionDetail
      ) {
        return {
          regionProvider: rawRegionDetail.regionProvider,
          columnName: rawRegionDetail.variableName,
          disambigColumnName: rawRegionDetail.disambigVariableName
        };
      });
      return regionMapping._regionDetails;
    })
    .otherwise(function(e) {
      console.log("error loading region ids", e);
    });
}
 beforeEach(function(done) {
     when.all([
         loadText('test/SDMX-JSON/dataflow-foo.json').then(function(text) { dataflowFoo = text; }),
         loadText('test/SDMX-JSON/data-foo-2013.json').then(function(text) { dataFoo = text; }),
         loadText('test/SDMX-JSON/data-foo-BD2-2013.json').then(function(text) { dataFooBD2 = text; }),
         loadText('test/SDMX-JSON/data-foo-BD2-2011_2013.json').then(function(text) { dataFooBD2t = text; }),
         loadText('test/SDMX-JSON/data-foo2-2013.json').then(function(text) { dataFoo2 = text; }),
         loadText('test/SDMX-JSON/data-nonspatial.json').then(function(text) { dataNonSpatial = text; }),
         loadText('data/regionMapping.json').then(function(text) { regionMappingJson = text; }),
         loadText('data/regionids/region_map-FID_LGA_2015_AUST_LGA_CODE15.json').then(function(text) { lgaData = text; })
     ]).then(function() {
         jasmine.Ajax.install();
         jasmine.Ajax.stubRequest(/.*/).andError(); // Fail all requests by default.
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/dataflow/FOO').andReturn({ responseText: dataflowFoo });
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2+BD_4.LGA_2013..A/all?startTime=2013&endTime=2013').andReturn({ responseText: dataFoo });
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2013&endTime=2013').andReturn({ responseText: dataFooBD2 });
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2011&endTime=2013').andReturn({ responseText: dataFooBD2t });
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO2/BD_2+BD_4..A../all?startTime=2013&endTime=2013').andReturn({ responseText: dataFoo2 });
         jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/NONSPATIAL/all/all').andReturn({ responseText: dataNonSpatial });
         jasmine.Ajax.stubRequest('data/regionMapping.json').andReturn({ responseText: regionMappingJson });
         jasmine.Ajax.stubRequest('data/regionids/region_map-FID_LGA_2015_AUST_LGA_CODE15.json').andReturn({ responseText: lgaData });
     }).then(done).otherwise(done.fail);
 });
Esempio n. 9
0
Promise.all = function(promises) {
    return Promise.resolve(when.all(promises));
};
Esempio n. 10
0
function isEnabledChanged(catalogItem) {
    var terria = catalogItem.terria;

    if (defined(catalogItem.creatorCatalogItem)) {
        catalogItem.creatorCatalogItem.isEnabled = catalogItem.isEnabled;
    }

    if (catalogItem.isEnabled) {
        terria.nowViewing.add(catalogItem);

        // Load this catalog item's data (if we haven't already) when it is enabled.
        // Don't actually enable until the load finishes.
        // Be careful not to call _enable multiple times or to call _enable
        // after the item has already been disabled.
        if (!defined(catalogItem._loadForEnablePromise)) {
            var resolvedOrRejected = false;
            var loadPromise = when.all([catalogItem.load(), catalogItem.waitForDisclaimerIfNeeded()]).then(function() {
                if (catalogItem.isEnabled) {
                    // If there's a separate now viewing item, remove this catalog item from the
                    // now viewing list, if it exists.
                    if (defined(catalogItem.nowViewingCatalogItem)) {
                        catalogItem.terria.nowViewing.items.remove(catalogItem);
                    }

                    catalogItem._enable();
                    catalogItem.terria.currentViewer.notifyRepaintRequired();
                    catalogItem.terria.currentViewer.addAttribution(catalogItem.attribution);
                    if(defined(catalogItem.imageryLayer)){
                      catalogItem.imageryLayer.featureInfoTemplate = catalogItem.featureInfoTemplate;
                    }
                }
            });

            raiseErrorOnRejectedPromise(catalogItem.terria, loadPromise);

            loadPromise.always(function() {
                resolvedOrRejected = true;
                catalogItem._loadForEnablePromise = undefined;
            });

            // Make sure we know about it when the promise already resolved/rejected.
            catalogItem._loadForEnablePromise = resolvedOrRejected ? undefined : loadPromise;
        }

        catalogItem.isShown = true;

        terria.analytics.logEvent('dataSource', 'added', catalogItem.name);
        catalogItem._enabledDate = Date.now();
    } else {
        catalogItem.isShown = false;

        // Disable this data item on the map, but only if the previous request to enable it has
        // actually gone through.
        if (!defined(catalogItem._loadForEnablePromise)) {
            catalogItem._disable();
            catalogItem.terria.currentViewer.removeAttribution(catalogItem.attribution);
        }

        terria.nowViewing.remove(catalogItem);

        var duration;
        if (catalogItem._enabledDate) {
            duration = ((Date.now() - catalogItem._enabledDate) / 1000.0) | 0;
        }
        terria.analytics.logEvent('dataSource', 'removed', catalogItem.name, duration);
    }

    catalogItem.terria.currentViewer.notifyRepaintRequired();
}
Esempio n. 11
0
CatalogItem.prototype.zoomToAndUseClock = function() {
    return when.all([this.zoomTo(), this.useClock()]);
};
NominatimSearchProviderViewModel.prototype.search = function(searchText) {
  if (!defined(searchText) || /^\s*$/.test(searchText)) {
    this.isSearching = false;
    this.searchResults.removeAll();
    return;
  }

  this.isSearching = true;
  this.searchResults.removeAll();
  this.searchMessage = undefined;

  this.terria.analytics.logEvent("search", "nominatim", searchText);

  // If there is already a search in progress, cancel it.
  if (defined(this._geocodeInProgress)) {
    this._geocodeInProgress.cancel = true;
    this._geocodeInProgress = undefined;
  }

  var bboxStr = "";

  if (defined(this.terria.cesium)) {
    var viewer = this.terria.cesium.viewer;
    var posUL = viewer.camera.pickEllipsoid(
      new Cartesian2(0, 0),
      Ellipsoid.WGS84
    );
    var posLR = viewer.camera.pickEllipsoid(
      new Cartesian2(viewer.canvas.width, viewer.canvas.height),
      Ellipsoid.WGS84
    );
    if (defined(posUL) && defined(posLR)) {
      posUL = Ellipsoid.WGS84.cartesianToCartographic(posUL);
      posLR = Ellipsoid.WGS84.cartesianToCartographic(posLR);
      bboxStr =
        "&viewbox=" +
        CesiumMath.toDegrees(posUL.longitude) +
        "," +
        CesiumMath.toDegrees(posUL.latitude) +
        "," +
        CesiumMath.toDegrees(posLR.longitude) +
        "," +
        CesiumMath.toDegrees(posLR.latitude);
    } else {
      bboxStr = "";
    }
  } else if (defined(this.terria.leaflet)) {
    var bbox = this.terria.leaflet.map.getBounds();
    bboxStr =
      "&viewbox=" +
      bbox.getWest() +
      "," +
      bbox.getNorth() +
      "," +
      bbox.getEast() +
      "," +
      bbox.getSouth();
  }
  var promiseBounded = loadJson(
    this.url +
      "search?q=" +
      searchText +
      bboxStr +
      "&bounded=1&format=json" +
      this.countryCodes +
      "&limit=" +
      this.limitBounded
  );
  var promiseOthers = loadJson(
    this.url +
      "search?q=" +
      searchText +
      "&format=json" +
      this.countryCodes +
      "&limit=" +
      this.limitOthers
  );

  var that = this;
  var geocodeInProgress = (this._geocodeInProgress = {
    cancel: false
  });

  return when
    .all([promiseBounded, promiseOthers])
    .then(function(result) {
      if (geocodeInProgress.cancel) {
        return;
      }
      that.isSearching = false;

      if (result.length === 0) {
        return;
      }

      var locations = [];

      // Locations in the bounded query go on top, locations elsewhere go undernearth
      var findDbl = function(elts, id) {
        return elts.filter(function(elt) {
          return elt.id === id;
        })[0];
      };

      for (var i = 0; i < result.length; ++i) {
        for (var j = 0; j < result[i].length; ++j) {
          var resource = result[i][j];

          var name = resource.display_name;
          if (!defined(name)) {
            continue;
          }

          if (!findDbl(locations, resource.place_id)) {
            locations.push(
              new SearchResultViewModel({
                id: resource.place_id,
                name: name,
                isImportant: true,
                clickAction: createZoomToFunction(that, resource)
              })
            );
          }
        }
      }

      that.searchResults.push.apply(that.searchResults, locations);

      if (that.searchResults.length === 0) {
        that.searchMessage = "Sorry, no locations match your search query.";
      }
    })
    .otherwise(function() {
      if (geocodeInProgress.cancel) {
        return;
      }

      that.isSearching = false;
      that.searchMessage =
        "An error occurred while searching.  Please check your internet connection or try again later.";
    });
};
Esempio n. 13
0
/**
 * Loads concept codes.
 * As they are loaded, each is processed into a tree of AbsCodes under an AbsConcept.
 * Returns a promise which, when resolved, indicates that item._concepts is complete.
 * The promise is cached, since the promise won't ever change for a given datasetId.
 * @private
 * @param  {AbsIttCatalogItem} item This catalog item.
 * @return {Promise} Promise.
 */
function loadConcepts(item) {
  if (!defined(item._loadConceptsPromise)) {
    var absConcepts = [];
    var promises = item._conceptIds
      .filter(function(conceptId) {
        return item.conceptsNotToLoad.indexOf(conceptId) === -1;
      })
      .map(function(conceptId) {
        var parameters = {
          method: "GetCodeListValue",
          datasetid: item.datasetId,
          concept: conceptId,
          format: "json"
        };
        var conceptCodesUrl = item._baseUrl + "?" + objectToQuery(parameters);

        return loadJson(conceptCodesUrl)
          .then(function(json) {
            // If this is a region type, only include valid region codes (eg. AUS, SA4, but not GCCSA).
            // Valid region codes must have a total population data file, eg. data/2011Census_TOT_SA4.csv
            var codes = json.codes;
            if (conceptId === item.regionTypeConcept) {
              codes = codes.filter(function(absCode) {
                return allowedRegionCodes.indexOf(absCode.code) >= 0;
              });
            }
            // We have loaded the file, process it into an AbsConcept.
            var concept = new AbsConcept({
              id: conceptId,
              codes: codes,
              filter: item.filter,
              allowMultiple: !(
                conceptId === item.regionTypeConcept ||
                item.uniqueValuedConcepts.indexOf(conceptId) >= 0
              ),
              activeItemsChangedCallback: function() {
                // Close any picked features, as the description of any associated with this catalog item may change.
                item.terria.pickedFeatures = undefined;
                rebuildData(item);
              }
            });
            // Give the concept its human-readable name.
            concept.name = getHumanReadableConceptName(
              item._conceptNamesMap,
              concept
            );
            absConcepts.push(concept);
          })
          .otherwise(throwLoadError.bind(null, item, "GetCodeListValue"));
      });

    item._loadConceptsPromise = when.all(promises).then(function() {
      // All the AbsConcept objects have been created, we just need to order them correctly and save them.
      // Put the region type concept first.
      var makeFirst = item.regionTypeConcept;
      absConcepts.sort(function(a, b) {
        return a.id === makeFirst
          ? -1
          : b.id === makeFirst
          ? 1
          : a.name > b.name
          ? 1
          : -1;
      });
      item._concepts = absConcepts;
    });
  }
  return item._loadConceptsPromise;
}
Esempio n. 14
0
Cesium.prototype._buildPickedFeatures = function(
  providerCoords,
  pickPosition,
  existingFeatures,
  featurePromises,
  imageryLayers,
  defaultHeight
) {
  var result = new PickedFeatures();

  result.providerCoords = providerCoords;
  result.pickPosition = pickPosition;

  result.allFeaturesAvailablePromise = when
    .all(featurePromises)
    .then(
      function(allFeatures) {
        result.isLoading = false;

        result.features = allFeatures.reduce(
          function(resultFeaturesSoFar, imageryLayerFeatures, i) {
            if (!defined(imageryLayerFeatures)) {
              return resultFeaturesSoFar;
            }

            var features = imageryLayerFeatures.map(
              function(feature) {
                if (defined(imageryLayers)) {
                  feature.imageryLayer = imageryLayers[i];
                }

                if (!defined(feature.position)) {
                  feature.position = Ellipsoid.WGS84.cartesianToCartographic(
                    pickPosition
                  );
                }

                // If the picked feature does not have a height, use the height of the picked location.
                // This at least avoids major parallax effects on the selection indicator.
                if (
                  !defined(feature.position.height) ||
                  feature.position.height === 0.0
                ) {
                  feature.position.height = defaultHeight;
                }
                return this._createFeatureFromImageryLayerFeature(feature);
              }.bind(this)
            );

            if (this.terria.showSplitter) {
              // Select only features from the same side or both sides of the splitter
              var screenPosition = this.computePositionOnScreen(
                result.pickPosition
              );
              var pickedSide = this.terria.getSplitterSideForScreenPosition(
                screenPosition
              );

              features = features.filter(function(feature) {
                var splitDirection = feature.imageryLayer.splitDirection;
                return (
                  splitDirection === pickedSide ||
                  splitDirection === ImagerySplitDirection.NONE
                );
              });
            }

            return resultFeaturesSoFar.concat(features);
          }.bind(this),
          defaultValue(existingFeatures, [])
        );
      }.bind(this)
    )
    .otherwise(function() {
      result.isLoading = false;
      result.error = "An unknown error occurred while picking features.";
    });

  return result;
};
WhyAmISpecialCatalogFunction.prototype.invoke = function() {
    var region = this._regionParameter.value;
    var data = this._dataParameter.getRegionDataValue();

    if (!defined(region)) {
        throw new TerriaError({
            title: 'Region not selected',
            message: 'You must select a Region.'
        });
    }

    var regionProvider = this._regionTypeParameter.value;

    var request = {
        algorithm: 'whyamispecial',
        boundaries_name: regionProvider.regionType,
        region_codes: data.regionCodes,
        columns: data.columnHeadings,
        table: data.table,
        parameters: {
            query: region.id
        }
    };

    var regionIndex = regionProvider.regions.indexOf(region);

    var regionName = region.id;
    if (regionIndex >= 0) {
        regionName = regionProvider.regionNames[regionIndex] || regionName;
    }

    var name = 'Why is ' + regionName + ' special?';

    var geoJsonPromise = regionProvider.getRegionFeature(this.terria, region);
    var invocationPromise = invokeTerriaAnalyticsService(this.terria, name, this.url, request);

    var that = this;
    return when.all([geoJsonPromise, invocationPromise]).then(function(allResults) {
        var geoJson = allResults[0];
        var invocationResult = allResults[1];

        var result = invocationResult.result;

        var catalogItem = new GeoJsonCatalogItem(that.terria);
        catalogItem.name = name;
        catalogItem.data = geoJson;
        catalogItem.dataUrl = invocationResult.url;

        var description = 'This is the result of invoking "' + that.name + '" at ' + invocationResult.startDate + ' with these parameters:\n\n';
        description += ' * ' + regionProvider.regionType + ' Region: ' + regionName + ' (' + region.id + ')\n';
        description += ' * Characteristics: ' + data.columnHeadings.join(', ') + '\n';

        catalogItem.description = description;

        var shortReport = '<p>These are the top characteristics that make ' + regionName + ' unique or special:</p>';

        for (var i = 0; i < 5 && i < result.columns.length; ++i) {
            var columnName = data.columnHeadings[result.columns[i]];
            var histogram = result.histograms[i];
            var binCounts = histogram.bin_counts;
            var binEdges = histogram.bin_edges;

            var chartData = [['Value', 'Count']];

            for (var j = 0; j < binCounts.length; ++j) {
                var leftEdge = binEdges[j];
                var rightEdge = binEdges[j + 1];
                if (!defined(rightEdge)) {
                    // Assume equally-spaced bins.
                    rightEdge = leftEdge + (binEdges[1] - binEdges[0]);
                }

                var center = (leftEdge + rightEdge) * 0.5;

                chartData.push([center, binCounts[j]]);
            }

            var percentile = result.percentiles[i];
            var percentileDescription = 'lower';
            if (percentile > 50) {
                percentile = 100 - percentile;
                percentileDescription = 'higher';
            }

            shortReport += '<collapsible title="' + columnName + '" open="' + (i === 0 ? 'true' : 'false') + '">\n';
            shortReport += '<p style="font-size: 0.8em">The value of ' + columnName + ' in ' + regionName + ' is ' + result.values[i] + '.</p>\n';
            shortReport += '<p style="font-size: 0.8em">Only ' + percentile.toFixed(1) + '% of regions have an equal or ' + percentileDescription + ' value.</p>\n';
            shortReport += '<chart title="Distribution of ' + columnName + ' across ' + regionProvider.regionType + ' regions" id="' + columnName + '" data=\'' + JSON.stringify(chartData) + '\' column-names="," y-column="1" styling="histogram" highlight-x="' + result.values[i] + '" hide-buttons="true"></chart>\n';
            shortReport += '</collapsible>\n';
        }

        catalogItem.shortReport = shortReport;
        catalogItem.isEnabled = true;
    });
};
function loadMapServer(catalogGroup) {
  function getJson(segment) {
    var uri = new URI(catalogGroup.url).segment(segment).addQuery("f", "json");
    return loadJson(proxyCatalogItemUrl(catalogGroup, uri.toString(), "1d"));
  }
  var terria = catalogGroup.terria;
  return when
    .all([getJson(""), getJson("layers"), getJson("legend")])
    .then(function(result) {
      var serviceJson = result[0];
      var layersJson = result[1];
      var legendJson = result[2];

      // Is this really a MapServer REST response?
      if (
        !serviceJson ||
        !serviceJson.layers ||
        !layersJson ||
        !layersJson.layers
      ) {
        throw new TerriaError({
          title: "Invalid ArcGIS Map Service",
          message:
            "\
An error occurred while invoking the ArcGIS Map Service.  The server's response does not appear to be a valid Map Service document.  \
<p>If you entered the link manually, please verify that the link is correct.</p>\
<p>If you did not enter this link manually, this error may indicate that the group you opened is temporarily unavailable or there is a \
problem with your internet connection.  Try opening the group again, and if the problem persists, please report it by \
sending an email to <a href=\"mailto:" +
            terria.supportEmail +
            '">' +
            terria.supportEmail +
            "</a>.</p>"
        });
      }

      var dataCustodian = catalogGroup.dataCustodian;
      if (
        !defined(dataCustodian) &&
        defined(serviceJson.documentInfo) &&
        defined(serviceJson.documentInfo.Author)
      ) {
        dataCustodian = serviceJson.documentInfo.Author;
      }
      if (
        catalogGroup.name === "Unnamed Item" &&
        defined(serviceJson.mapName) &&
        serviceJson.mapName.length > 0
      ) {
        catalogGroup.name = serviceJson.mapName;
      }

      addLayersRecursively(
        catalogGroup,
        serviceJson,
        layersJson,
        legendJson,
        -1,
        layersJson.layers,
        catalogGroup,
        dataCustodian
      );
    })
    .otherwise(function(e) {
      throw new TerriaError({
        sender: catalogGroup,
        title: "Group is not available",
        message:
          '\
An error occurred while invoking the ArcGIS Map Service. \
<p>If you entered the link manually, please verify that the link is correct.</p>\
<p>This error may also indicate that the server does not support <a href="http://enable-cors.org/" target="_blank">CORS</a>.  If this is your \
server, verify that CORS is enabled and enable it if it is not.  If you do not control the server, \
please contact the administrator of the server and ask them to enable CORS.  Or, contact the ' +
          terria.appName +
          ' \
team by emailing <a href="mailto:' +
          terria.supportEmail +
          '">' +
          terria.supportEmail +
          "</a> \
and ask us to add this server to the list of non-CORS-supporting servers that may be proxied by " +
          terria.appName +
          ' \
itself.</p>\
<p>If you did not enter this link manually, this error may indicate that the group you opened is temporarily unavailable or there is a \
problem with your internet connection.  Try opening the group again, and if the problem persists, please report it by \
sending an email to <a href="mailto:' +
          terria.supportEmail +
          '">' +
          terria.supportEmail +
          "</a>.</p>"
      });
    });
}
Esempio n. 17
0
TableStyle.prototype.updateFromJson = function(json, options) {
    var promises = [updateFromJson(this, json, options)];
    this.columns = objectToTableColumnStyle(json, promises, options);
    return when.all(promises);
};
Esempio n. 18
0
CkanCatalogGroup.prototype._load = function() {
    if (!defined(this.url) || this.url.length === 0) {
        return undefined;
    }

    var that = this;

    var promises = [];
    if (!(defined(this.filterQuery) && Array.isArray(this.filterQuery) && (typeof this.filterQuery[0] === 'string' || typeof this.filterQuery[0] === 'object'))) {
        throw new TerriaError({
                title: 'Error loading CKAN catalogue',
                message: 'The definition for this CKAN catalogue does not have a valid filter query.'
            });

    }

    const results = [];

    this.filterQuery.forEach(function(query) {
        var uri = new URI(that.url)
            .segment('api/3/action/package_search')
            .addQuery({ rows: 100000, sort: 'metadata_created asc' });

        if (typeof query === 'object') {
            // query is an object of non-encoded parameters, like { fq: "res_format:wms OR WMS" }
            Object.keys(query).forEach(key =>  uri.addQuery(key, query[key]));
        }

        let start = 0;

        function requestNext() {
            var nextUri = uri.clone().addQuery({ start: start });

            var uristring = nextUri.toString();

            if (typeof query === 'string') {
                // query is expected to be URL-encoded and begin with a query like 'fq='
                uristring += '&' + query;
            }

            return loadJson(proxyCatalogItemUrl(that, uristring, '1d')).then(function(pageResults) {
                if (pageResults && pageResults.result && pageResults.result.results) {
                    const thisPage = pageResults.result.results;
                    for (let i = 0; i < thisPage.length; ++i) {
                        results.push(thisPage[i]);
                    }

                    start += thisPage.length;

                    if (start < pageResults.result.count) {
                        return requestNext();
                    }
                }
            });
        }

        promises.push(requestNext().then(function() {
            return results;
        }));
    });

    return when.all(promises).then( function(queryResults) {
        if (!defined(queryResults)) {
            return;
        }

        var allResults = [];

        for (var p = 0; p < queryResults.length; p++) {
            var queryResult = queryResults[p];
            for (var i = 0; i < queryResult.length; ++i) {
                allResults.push(queryResult[i]);
            }
        }

        if (that.filterByWmsGetCapabilities) {
            return when(filterResultsByGetCapabilities(that, allResults), function() {
                populateGroupFromResults(that, allResults);
            });
        } else {
            populateGroupFromResults(that, allResults);
        }
    }).otherwise(function(e) {
        throw new TerriaError({
            sender: that,
            title: that.name,
            message: '\
Couldn\'t retrieve packages from this CKAN server.<br/><br/>\
If you entered the URL manually, please double-check it.<br/><br/>\
If it\'s your server, make sure <a href="http://enable-cors.org/" target="_blank">CORS</a> is enabled.<br/><br/>\
Otherwise, if reloading doesn\'t fix it, please report the problem by sending an email to <a href="mailto:'+that.terria.supportEmail+'">'+that.terria.supportEmail+'</a> with the technical details below.  Thank you!<br/><br/>\
<pre>' + formatError(e) + '</pre>'
        });
    });
};
Esempio n. 19
0
 knockout.getObservable(this, 'isOpen').subscribe(function(newValue) {
     // Load this group's items (if we haven't already) when it is opened.
     if (newValue) {
         raiseErrorOnRejectedPromise(that.terria, when.all([that.waitForDisclaimerIfNeeded(), that.load()]));
     }
 });
Esempio n. 20
0
function pickFeatures(leaflet, latlng, tileCoordinates, existingFeatures) {
  if (defined(leaflet._pickedFeatures)) {
    // Picking is already in progress.
    return;
  }

  leaflet._pickedFeatures = new PickedFeatures();

  if (defined(existingFeatures)) {
    leaflet._pickedFeatures.features = existingFeatures;
  }

  // We run this later because vector click events and the map click event can come through in any order, but we can
  // be reasonably sure that all of them will be processed by the time our runLater func is invoked.
  var cleanup = runLater(function() {
    // Set this again just in case a vector pick came through and reset it to the vector's position.
    var newPickLocation = Ellipsoid.WGS84.cartographicToCartesian(
      pickedLocation
    );
    var mapInteractionModeStack = leaflet.terria.mapInteractionModeStack;
    if (
      defined(mapInteractionModeStack) &&
      mapInteractionModeStack.length > 0
    ) {
      mapInteractionModeStack[
        mapInteractionModeStack.length - 1
      ].pickedFeatures.pickPosition = newPickLocation;
    } else if (defined(leaflet.terria.pickedFeatures)) {
      leaflet.terria.pickedFeatures.pickPosition = newPickLocation;
    }

    // Unset this so that the next click will start building features from scratch.
    leaflet._pickedFeatures = undefined;
  });

  var activeItems = leaflet.terria.nowViewing.items;
  tileCoordinates = defaultValue(tileCoordinates, {});

  var pickedLocation = Cartographic.fromDegrees(latlng.lng, latlng.lat);
  leaflet._pickedFeatures.pickPosition = Ellipsoid.WGS84.cartographicToCartesian(
    pickedLocation
  );

  // We want the all available promise to return after the cleanup one to make sure all vector click events have resolved.
  var promises = [cleanup].concat(
    activeItems
      .filter(function(item) {
        return (
          item.isEnabled &&
          item.isShown &&
          defined(item.imageryLayer) &&
          defined(item.imageryLayer.pickFeatures)
        );
      })
      .map(function(item) {
        var imageryLayerUrl = item.imageryLayer.imageryProvider.url;
        var longRadians = CesiumMath.toRadians(latlng.lng);
        var latRadians = CesiumMath.toRadians(latlng.lat);

        return when(
          tileCoordinates[imageryLayerUrl] ||
            item.imageryLayer.getFeaturePickingCoords(
              leaflet.map,
              longRadians,
              latRadians
            )
        ).then(function(coords) {
          return item.imageryLayer
            .pickFeatures(
              coords.x,
              coords.y,
              coords.level,
              longRadians,
              latRadians
            )
            .then(function(features) {
              return {
                features: features,
                imageryLayer: item.imageryLayer,
                coords: coords
              };
            });
        });
      })
  );

  var pickedFeatures = leaflet._pickedFeatures;

  pickedFeatures.allFeaturesAvailablePromise = when
    .all(promises)
    .then(function(results) {
      // Get rid of the cleanup promise
      var promiseResult = results.slice(1);

      pickedFeatures.isLoading = false;
      pickedFeatures.providerCoords = {};

      var filteredResults = promiseResult.filter(function(result) {
        return defined(result.features) && result.features.length > 0;
      });

      pickedFeatures.providerCoords = filteredResults.reduce(function(
        coordsSoFar,
        result
      ) {
        coordsSoFar[result.imageryLayer.imageryProvider.url] = result.coords;
        return coordsSoFar;
      },
      {});

      pickedFeatures.features = filteredResults.reduce(function(
        allFeatures,
        result
      ) {
        if (leaflet.terria.showSplitter) {
          // Skip unless the layer is on the picked side or belongs to both sides of the splitter
          var screenPosition = leaflet.computePositionOnScreen(
            pickedFeatures.pickPosition
          );
          var pickedSide = leaflet.terria.getSplitterSideForScreenPosition(
            screenPosition
          );
          var splitDirection = result.imageryLayer.splitDirection;

          if (
            !(
              splitDirection === pickedSide ||
              splitDirection === ImagerySplitDirection.NONE
            )
          ) {
            return allFeatures;
          }
        }

        return allFeatures.concat(
          result.features.map(function(feature) {
            feature.imageryLayer = result.imageryLayer;

            // For features without a position, use the picked location.
            if (!defined(feature.position)) {
              feature.position = pickedLocation;
            }

            return leaflet._createFeatureFromImageryLayerFeature(feature);
          })
        );
      },
      pickedFeatures.features);
    })
    .otherwise(function(e) {
      pickedFeatures.isLoading = false;
      pickedFeatures.error =
        "An unknown error occurred while picking features.";

      throw e;
    });

  var mapInteractionModeStack = leaflet.terria.mapInteractionModeStack;
  if (defined(mapInteractionModeStack) && mapInteractionModeStack.length > 0) {
    mapInteractionModeStack[mapInteractionModeStack.length - 1].pickedFeatures =
      leaflet._pickedFeatures;
  } else {
    leaflet.terria.pickedFeatures = leaflet._pickedFeatures;
  }
}
Esempio n. 21
0
/**
 * Loads all the datafiles for this catalog item, given the active concepts.
 * @private
 * @param  {AbsIttCatalogItem} item The AbsIttCatalogItem instance.
 * @return {Promise} A Promise which resolves to an object of TableStructures for each loaded dataset,
 * with the total populations as the final one; and the active combinations.
 */
function loadDataFiles(item) {
  // An array of arrays, indexed by activeItemsPerConcept[conceptIndex][codeIndex].
  var activeCodesPerConcept = item._concepts.map(function(concept) {
    return concept.activeItems;
  });

  // If any one of the concepts has no active selection, there will be no files to load.
  for (var i = activeCodesPerConcept.length - 1; i >= 0; i--) {
    if (activeCodesPerConcept[i].length === 0) {
      return when();
    }
  }

  // If there is no valid region selected (including when there are two!), stop.
  if (!defined(getActiveRegionTypeCode(item))) {
    return when();
  }

  // Find every possible combination, taking a single code from each concept.
  var activeCombinations = arrayProduct(activeCodesPerConcept);

  // Construct the 'and' part of the requests by combining concept.id and the AbsCode.name,
  // eg. and=REGIONTYPE.SA4,AGE.A04,MEASURE.3
  var andParameters = activeCombinations.map(function(codes) {
    return codes
      .map(function(code, index) {
        return code.concept.id + "." + code.code;
      })
      .join(",");
  });

  var loadDataPromises = andParameters.map(function(andParameter) {
    // Build a promise which resolves once this datafile has loaded (unless we have cached this promise already).
    // Note in the original there was different cacheing stuff... but not sure if it was being used?
    if (!defined(item._loadDataFilePromise[andParameter])) {
      var parameters = {
        method: "GetGenericData",
        datasetid: item.datasetId,
        and: andParameter,
        or: item.regionConcept,
        format: "csv"
      };
      var url = item._baseUrl + "?" + objectToQuery(parameters);
      item._loadDataFilePromise[andParameter] = loadText(url).then(
        loadTableStructure.bind(undefined, item)
      );
    }
    return item._loadDataFilePromise[andParameter];
  });

  var totalPopulationsUrl =
    item.regionPopulationsUrlPrefix + getActiveRegionTypeCode(item) + ".csv";
  loadDataPromises.push(
    loadText(totalPopulationsUrl).then(loadTableStructure.bind(undefined, item))
  );

  return when.all(loadDataPromises).then(function(tableStructures) {
    return {
      tableStructures: tableStructures,
      activeCombinations: activeCombinations
    };
  });
}
Esempio n. 22
0
function addUserFiles(files, terria, viewState, fileType) {
    const dataType = fileType || getDataType().localDataType[0];
    if (!defined(files)) {
        terria.error.raiseEvent(new TerriaError({
                title: 'File API not supported',
                message: '\
Sorry, your web browser does not support the File API, which '+terria.appName+' requires in order to \
add data from a file on your system.  Please upgrade your web browser.  For the best experience, we recommend \
<a href="http://www.microsoft.com/ie" target="_blank">Internet Explorer 11</a> or the latest version of \
<a href="http://www.google.com/chrome" target="_blank">Google Chrome</a> or \
<a href="http://www.mozilla.org/firefox" target="_blank">Mozilla Firefox</a>.'
            }));
    }

    const promises = [];
    const tempCatalogItemList = [];

    for (let i = 0; i < files.length; ++i) {
        const file = files[i];
        const tempCatalogItem = new ResultPendingCatalogItem(terria);
        tempCatalogItem.name = file.name;
        tempCatalogItem.description = "Loading file...";
        terria.catalog.userAddedDataGroup.add(tempCatalogItem);
        terria.catalog.userAddedDataGroup.isOpen = true;

        terria.analytics.logEvent('uploadFile', 'browse', file.name);

        let loadPromise;
        if (file.name.toUpperCase().indexOf('.JSON') !== -1) {
            const promise = readJson(file).then(json => {
                if (json.catalog || json.services) {
                    // This is an init file.
                    return terria.addInitSource(json).then(() => {
                        tempCatalogItem.isEnabled = false;
                        tempCatalogItemList.splice(tempCatalogItemList.indexOf(tempCatalogItem), 1);
                        terria.catalog.userAddedDataGroup.remove(tempCatalogItem);
                    });
                }
                loadPromise = addUserCatalogMember(terria, createCatalogItemFromFileOrUrl(terria, viewState, file, dataType.value, true));
            });
            loadPromise = raiseErrorOnRejectedPromise(terria, promise);
            promises.push(loadPromise);
        } else {
            loadPromise = addUserCatalogMember(terria, createCatalogItemFromFileOrUrl(terria, viewState, file, dataType.value, true));
            promises.push(loadPromise);
        }
        tempCatalogItem.loadPromise = loadPromise;
        tempCatalogItem.isEnabled = true;
        tempCatalogItemList.push(tempCatalogItem);
    }

    return when.all(promises, addedItems => {
        // if addedItem has only undefined item, means init files
        // have been uploaded
        if(addedItems.every(item=>item === undefined)){
            viewState.openAddData();
        } else{
            const items = addedItems.filter(item => item && !(item instanceof TerriaError));
            tempCatalogItemList.forEach(function(value) { terria.catalog.userAddedDataGroup.remove(value); });
            return items;
        }
    });
}