github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/util/locations.ts (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  import _ from "lodash";
    12  
    13  import { LocalityTier, LocalityTree } from "src/redux/localities";
    14  import { ILocation, LocationTree } from "src/redux/locations";
    15  import * as vector from "src/util/vector";
    16  
    17  /*
    18   * getLocation retrieves the location for a given locality tier from the
    19   * LocationTree, or null if none is found.
    20   */
    21  export function getLocation(locations: LocationTree, tier: LocalityTier) {
    22    if (!locations[tier.key]) {
    23      return null;
    24    }
    25  
    26    return locations[tier.key][tier.value];
    27  }
    28  
    29  /*
    30   * hasLocation is a predicate to determine if a given locality tier exists in
    31   * the LocationTree.
    32   */
    33  export function hasLocation(locations: LocationTree, tier: LocalityTier) {
    34    return !_.isNil(getLocation(locations, tier));
    35  }
    36  
    37  /*
    38   * findMostSpecificLocation searches for a location matching the given locality
    39   * tiers in the LocationTree.  It tries to find the most specific location that
    40   * applies, and thus begins searching from the end of the list of tiers for a
    41   * tier with a matching location.  Returns null if none is found.
    42   */
    43  export function findMostSpecificLocation(locations: LocationTree, tiers: LocalityTier[]) {
    44    let currentIndex = tiers.length - 1;
    45    while (currentIndex >= 0) {
    46      const currentTier = tiers[currentIndex];
    47      const location = getLocation(locations, currentTier);
    48  
    49      if (!_.isNil(location)) {
    50        return location;
    51      }
    52  
    53      currentIndex -= 1;
    54    }
    55  
    56    return null;
    57  }
    58  
    59  /*
    60   * findOrCalculateLocation tries to place a locality on the map.  If there is
    61   * no location assigned to the locality itself, calculate the centroid of the
    62   * children.
    63   */
    64  export function findOrCalculateLocation(locations: LocationTree, locality: LocalityTree) {
    65    // If a location is assigned to this locality, return it.
    66    const thisTier = locality.tiers[locality.tiers.length - 1];
    67    const thisLocation = getLocation(locations, thisTier);
    68    if (!_.isNil(thisLocation)) {
    69      return thisLocation;
    70    }
    71  
    72    // If this locality has nodes directly, we can't calculate a location; bail.
    73    if (!_.isEmpty(locality.nodes)) {
    74      return null;
    75    }
    76  
    77    // If this locality has no child localities, we can't calculate a location.
    78    // Note, this shouldn't ever actually happen.
    79    if (_.isEmpty(locality.localities)) {
    80      return null;
    81    }
    82  
    83    // Find (or calculate) the location of each child locality.
    84    const childLocations: ILocation[] = [];
    85    _.values(locality.localities).forEach((tier) => {
    86      _.values(tier).forEach((child) => {
    87        childLocations.push(findOrCalculateLocation(locations, child));
    88      });
    89    });
    90  
    91    // If any child location is missing, bail.
    92    if (_.some(childLocations, _.isNil)) {
    93      return null;
    94    }
    95  
    96    // Calculate the centroid of the child locations.
    97    let centroid: [number, number] = [0, 0];
    98    childLocations.forEach((loc) => centroid = vector.add(centroid, [loc.longitude, loc.latitude]));
    99    centroid = vector.mult(centroid, 1 / childLocations.length);
   100    return { longitude: centroid[0], latitude: centroid[1] };
   101  }