geojson#Feature TypeScript Examples

The following examples show how to use geojson#Feature. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: analysis-utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
/**
 * Creates Analysis result legend based on data returned from API.
 *
 * The equal interval method takes the maximum values minus the minimum
 * and divides the result by the number of classes, which is the length
 * of colors array.
 *
 * Finally the function calculates the upper end of each class interval
 * and assigns a color.
 *
 * @return LegendDefinition
 */
export function createLegendFromFeatureArray(
  features: Feature[],
  statistic: AggregationOperations,
): LegendDefinition {
  // Extract values based on aggregation operation.
  const stats: number[] = features.map(f =>
    f.properties && f.properties[statistic] ? f.properties[statistic] : 0,
  );

  const maxNum = Math.max(...stats);
  const minNum = Math.min(...stats);

  const colors = ['#fee5d9', '#fcae91', '#fb6a4a', '#de2d26', '#a50f15'];

  const delta = (maxNum - minNum) / colors.length;

  const legend: LegendDefinition = colors.map((color, index) => {
    const breakpoint = Math.ceil(minNum + (index + 1) * delta);

    // Make sure you don't have a value greater than maxNum.
    const value = Math.min(breakpoint, maxNum);

    return { value, color };
  });

  return legend;
}
Example #2
Source File: analysis-utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
/**
 * Computes the feature property value according to the scale, offset values and statistic property
 *
 * @return Feature
 */
export function scaleFeatureStat(
  feature: Feature,
  scale: number,
  offset: number,
  statistic: AggregationOperations,
): Feature {
  const { properties } = feature;
  if (!properties) {
    return feature;
  }

  const scaledValue: number = get(properties, statistic) * scale + offset;

  const scaledValueProperties = {
    ...properties,
    [statistic]: scaledValue,
  };
  const scaledValueFeature: Feature = {
    ...feature,
    properties: scaledValueProperties,
  };

  return scaledValueFeature;
}
Example #3
Source File: analysis-utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
export async function fetchApiData(
  url: string,
  apiData: ApiData | AlertRequest,
): Promise<Array<KeyValueResponse | Feature>> {
  return (
    await fetch(url, {
      method: 'POST',
      cache: 'no-cache',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      // body data type must match "Content-Type" header
      body: JSON.stringify(apiData),
    })
  )
    .text()
    .then(message => {
      try {
        return JSON.parse(message);
      } catch (e) {
        // In some cases the response isn't valid JSON.
        // In those cases, just wrap the full response in an object.
        return {
          message,
        };
      }
    });
}
Example #4
Source File: analysis-utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
function mergeFeaturesByProperty(
  baselineFeatures: Feature[],
  aggregateData: Array<object>,
  id: string,
): Feature[] {
  const features = baselineFeatures.map(feature1 => {
    const aggregateProperties = aggregateData.filter(
      item => get(item, id) === get(feature1, ['properties', id]) && item,
    );

    const filteredProperties = aggregateProperties.map(filteredProperty => {
      // We use geometry from response. If not, use whole admin boundary.
      const filteredGeometry = get(filteredProperty, 'geometry');

      const propertyItems = filteredGeometry
        ? omit(filteredProperty, 'geometry')
        : filteredProperty;

      const properties = {
        ...get(feature1, 'properties'),
        ...propertyItems,
        impactValue: get(feature1, 'properties.data'),
      };

      const feature = filteredGeometry
        ? { ...feature1, geometry: filteredGeometry, properties }
        : { ...feature1, properties };

      return feature;
    });

    return filteredProperties;
  });

  return flatten(features);
}
Example #5
Source File: csv.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
export function parseCsv(text: string): Feature[] {
  // first parse the header to guess the delimiter
  // note that we do that to not rely on Papaparse logic for guessing delimiter
  let delimiter
  try {
    const header = text.split('\n')[0]
    const result = Papa.parse(header, {
      header: false,
    })
    delimiter = result.meta.delimiter
  } catch (e) {
    throw new Error('CSV parsing failed: the delimiter could not be guessed')
  }

  const parsed = Papa.parse(text, {
    header: true,
    skipEmptyLines: true,
    delimiter,
  })
  if (parsed.errors.length) {
    throw new Error(
      'CSV parsing failed for the following reasons:\n' +
        parsed.errors
          .map(
            (error) =>
              `* ${error.message} at row ${error.row}, column ${error.index}`
          )
          .join('\n')
    )
  }
  return (parsed.data as any[]).map(jsonToGeojsonFeature)
}
Example #6
Source File: dataset-validation-page.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
loadSampleFeature() {
    this.fileUploadApiService
      .getSampleFeature(
        this.rootId.toString(),
        this.dataset.name,
        this.featureIndex,
        this.encoding,
        viewSrs,
        this.crs
      )
      .subscribe((feature: Feature) => (this.geoJSONData = feature))
  }
Example #7
Source File: map.vector.ts    From diablo2 with MIT License 6 votes vote down vote up
export function toGeoJson(c: LevelData, act: Act): GeoJSON.FeatureCollection {
  const features: Feature[] = [];

  for (const z of c.levels.values()) {
    const mapAct = ActUtil.fromLevel(z.id);
    if (mapAct !== act) continue;

    const latLng = LevelBounds.sourceToLatLng(z.offset.x, z.offset.y);
    features.push({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [latLng.lng, latLng.lat] },
      properties: { name: z.name, type: 'level-name' },
    });

    for (const obj of z.objects) {
      const feat = makeFeature(obj, z);
      if (feat == null || feat === false) continue;
      features.push(feat);
    }
  }
  return toFeatureCollection(features);
}
Example #8
Source File: map.vector.ts    From diablo2 with MIT License 6 votes vote down vote up
function makeFeature(obj: Diablo2LevelObject, z: Diablo2Level): GeoJSON.Feature | null | false {
  if (obj.type === 'object') {
    const fm = MapObjects.get(obj.id);
    if (fm) return toFeature(obj, z, fm);
  }

  for (const filter of MapFeatureFilter) {
    const fm = filter(obj);
    if (fm === false) return null;
    if (fm) return toFeature(obj, z, fm);
  }

  return null;
}
Example #9
Source File: map.vector.ts    From diablo2 with MIT License 6 votes vote down vote up
function toFeature(obj: Diablo2LevelObject, z: Diablo2Level, fm: FeatureMaker): GeoJSON.Feature {
  if (fm.feature === 'polygon') {
    return {
      type: 'Feature',
      geometry: pointToPolygon(z.offset.x + obj.x, z.offset.y + obj.y, fm.width, fm.height, fm.xOffset, fm.yOffset),
      properties: { ...obj, type: fm.layer, name: `${toHex(obj.id)} ${obj.name ?? ''}` },
    };
  }

  if (fm.feature === 'point') {
    const latLng = LevelBounds.sourceToLatLng(z.offset.x + obj.x, z.offset.y + obj.y);
    return {
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [latLng.lng, latLng.lat] },
      properties: { ...obj, type: fm.layer, name: `${toHex(obj.id)} ${obj.name ?? ''}` },
    };
  }

  throw new Error('Unknown feature type: ' + fm);
}
Example #10
Source File: excel.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
/**
 * This will read the first sheet of the excel workbook and expect the first
 * line to contain the properties names
 * @param buffer
 */
export function parseExcel(buffer: ArrayBuffer): Feature[] {
  const workbook = XLSX.read(buffer)
  const sheet = workbook.Sheets[workbook.SheetNames[0]]

  const json = XLSX.utils.sheet_to_json(sheet)
  if (!json.length) {
    return []
  }

  return json.map(jsonToGeojsonFeature)
}
Example #11
Source File: RegionLabelLayer.tsx    From Teyvat.moe with GNU General Public License v3.0 6 votes vote down vote up
_RegionLabelLayer: FunctionComponent<RegionLabelLayerProps> = ({ displayed, zoomLevel }) => {
  const classes = useStyles();

  const map = useMap();
  const layerReference = useRef<GeoJSONLeaflet | null>(null);

  useEffect(() => {
    if (layerReference.current != null) {
      if (displayed) {
        layerReference.current.addTo(map);
      } else {
        layerReference.current.removeFrom(map);
      }
    }
  }, [map, displayed]);

  const pointToLayer = (featureData: Feature<Point, any>, latLng: LatLng) => {
    const html = renderToString(<RegionLabel featureData={featureData} zoomLevel={zoomLevel} />);

    return LeafletMarker([latLng.lng, latLng.lat], {
      interactive: false, // Allow clicks to pass through.
      icon: LeafletDivIcon({
        html,
        className: classes.regionLabelMarker,
      }),
      zIndexOffset: -900,
    });
  };

  return (
    <GeoJSON
      ref={layerReference}
      key={zoomLevel}
      pointToLayer={pointToLayer}
      data={RegionLabelData as GeoJsonObject}
    />
  );
}
Example #12
Source File: mapSelectors.ts    From react-tutorials with MIT License 6 votes vote down vote up
getMapDataFromFile = () =>
  new Promise((resolve) =>
    fetch('/data/world-110m.json').then((response) => {
      if (response.status !== 200) {
        // eslint-disable-next-line no-console
        console.log(`Houston, we have a problem! ${response.status}`)
        return
      }
      response.json().then((worldData) => {
        const mapFeatures: Array<Feature<Geometry | null>> = ((feature(worldData, worldData.objects.countries) as unknown) as FeatureCollection).features
        resolve(setMapObject(mapFeatures))
      })
    })
  )
Example #13
Source File: geojson.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
/**
 * This parser supports both Geojson Feature collections or arrays
 * of Features
 * @param text
 */
export function parseGeojson(text: string): Feature[] {
  const parsed = JSON.parse(text)
  const features =
    parsed.type === 'FeatureCollection' ? parsed.features : parsed
  if (!Array.isArray(features)) {
    throw new Error(
      'Could not parse GeoJSON, expected a features collection or an array of features at root level'
    )
  }
  return features
}
Example #14
Source File: json.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
/**
 * This parser only supports arrays of simple flat objects with properties
 * @param text
 */
export function parseJson(text: string): Feature[] {
  const parsed = JSON.parse(text)
  if (!Array.isArray(parsed)) {
    throw new Error('Could not parse JSON, expected an array at root level')
  }
  return (parsed as any[]).map(jsonToGeojsonFeature)
}
Example #15
Source File: WorldMapAtlas.tsx    From react-tutorials with MIT License 6 votes vote down vote up
WorldMapAtlas = () => {
  const [geographies, setGeographies] = useState<[] | Array<Feature<Geometry | null>>>([])

  useEffect(() => {
    fetch('/data/world-110m.json').then((response) => {
      if (response.status !== 200) {
        // eslint-disable-next-line no-console
        console.log(`Houston we have a problem: ${response.status}`)
        return
      }
      response.json().then((worldData) => {
        const mapFeatures: Array<Feature<Geometry | null>> = ((feature(worldData, worldData.objects.countries) as unknown) as FeatureCollection).features
        setGeographies(mapFeatures)
      })
    })
  }, [])

  const projection = geoEqualEarth().scale(scale).translate([cx, cy]).rotate([0, 0])

  return (
    <>
      <svg width={scale * 3} height={scale * 3} viewBox="0 0 800 450">
        <g>
          {(geographies as []).map((d, i) => (
            <path
              key={`path-${uuid()}`}
              d={geoPath().projection(projection)(d) as string}
              fill={`rgba(38,50,56,${(1 / (geographies ? geographies.length : 0)) * i})`}
              stroke="aliceblue"
              strokeWidth={0.5}
            />
          ))}
        </g>
      </svg>
    </>
  )
}
Example #16
Source File: json.ts    From geonetwork-ui with GNU General Public License v2.0 6 votes vote down vote up
export function jsonToGeojsonFeature(object: { [key: string]: any }): Feature {
  const { id, properties } = Object.keys(object)
    .map((property) => (property ? property : 'unknown')) //prevent empty strings
    .reduce(
      (prev, curr) =>
        curr.toLowerCase().endsWith('id')
          ? {
              ...prev,
              id: object[curr],
            }
          : {
              ...prev,
              properties: { ...prev.properties, [curr]: object[curr] },
            },
      { id: undefined, properties: {} }
    )
  return {
    type: 'Feature',
    geometry: null,
    properties,
    ...(id !== undefined && { id }),
  }
}
Example #17
Source File: geospatialService.ts    From react-flight-tracker with MIT License 5 votes vote down vote up
private calculatePath = (stateVectors: IStateVectorData) => {

    const features: Array<Feature<Point, GeoJsonProperties>> = [];

    for (var stateVector of stateVectors.states) {

      // Setup last position time in ms
      var lastPositionTime = this.pathPredictionCounter

      // Setup altitude in m
      var altitude = stateVector.geo_altitude;
      if ((altitude === null) || (altitude < 0))
        altitude = stateVector.baro_altitude;
      if ((altitude === null) || (altitude < 0))
        altitude = 0;

      // Setup vertical rate
      var verticalRate = stateVector.vertical_rate ? stateVector.vertical_rate : 0.0;
      if (verticalRate < 0)
        verticalRate *= -1;

      const origin: Array<number> = [stateVector.longitude ? stateVector.longitude : 0, stateVector.latitude ? stateVector.latitude : 0]
      const velocity = stateVector.velocity ? stateVector.velocity : 0;

      var distance = (velocity * lastPositionTime) / 1000;

      // Try to adjust the distance to the vertical rate
      if (verticalRate !== 0)
        distance = distance - (verticalRate * (lastPositionTime / 1000));

      // Try to adjust the distance to the altitude
      if (altitude > 0)
        distance = (distance * earthRadius) / (earthRadius + altitude);

      const bearing = stateVector.true_track ? stateVector.true_track : 0;

      // Calculate the destination
      const feature = destination(
        origin,
        distance,
        bearing,
        {
          units: "meters"
        }
      );

      // Adding the ICAO24 prop to the feature so that a corresponding assignment is possible later
      var properties: GeoJsonProperties = {
        ['icao24']: stateVector.icao24
      };
      feature.properties = properties;

      // Push the feature to the collection
      features.push(feature);
    }

    // Increase counter time
    this.pathPredictionCounter += this.pathPredictionInterval;

    // Execute callbacks
    Object.entries(this.pathPredictionUpdatedSubscriberDictionary).forEach(([key, value], index) => value(features))
  };
Example #18
Source File: dataset-validation-page.ts    From geonetwork-ui with GNU General Public License v2.0 5 votes vote down vote up
geoJSONBBox: Feature
Example #19
Source File: RotatingRoundWorldMap.tsx    From react-tutorials with MIT License 5 votes vote down vote up
WorldMap = () => {
  const [geographies, setGeographies] = useState<[] | Array<Feature<Geometry | null>>>([])
  const [rotation, setRotation] = useState<number>(initRotation)
  const [isRotate, setIsRotate] = useState<Boolean>(false)

  useEffect(() => {
    fetch('/data/world-110m.json').then((response) => {
      if (response.status !== 200) {
        // eslint-disable-next-line no-console
        console.log(`Houston we have a problem: ${response.status}`)
        return
      }
      response.json().then((worldData) => {
        const mapFeatures: Array<Feature<Geometry | null>> = ((feature(worldData, worldData.objects.countries) as unknown) as FeatureCollection).features
        setGeographies(mapFeatures)
      })
    })
  }, [])

  // geoEqualEarth
  // geoOrthographic
  const projection = geoOrthographic().scale(scale).translate([cx, cy]).rotate([rotation, 0])

  AnimationFrame(() => {
    if (isRotate) {
      let newRotation = rotation
      if (rotation >= 360) {
        newRotation = rotation - 360
      }
      setRotation(newRotation + 0.2)
      // console.log(`rotation: ${  rotation}`)
    }
  })

  return (
    <>
      <Button
        size="medium"
        color="primary"
        startIcon={<PlayCircleFilledWhiteIcon />}
        onClick={() => {
          setIsRotate(true)
        }}
      />
      <svg width={scale * 3} height={scale * 3} viewBox="0 0 800 450">
        <g>
          <circle fill="#f2f2f2" cx={cx} cy={cy} r={scale} />
        </g>
        <g>
          {(geographies as []).map((d, i) => (
            <path
              key={`path-${uuid()}`}
              d={geoPath().projection(projection)(d) as string}
              fill={`rgba(38,50,56,${(1 / (geographies ? geographies.length : 0)) * i})`}
              stroke="aliceblue"
              strokeWidth={0.5}
            />
          ))}
        </g>
      </svg>
    </>
  )
}
Example #20
Source File: dataset-validation-page.ts    From geonetwork-ui with GNU General Public License v2.0 5 votes vote down vote up
geoJSONData: Feature
Example #21
Source File: data-import-validation-map-panel.component.ts    From geonetwork-ui with GNU General Public License v2.0 5 votes vote down vote up
@Input() geoJson?: Feature
Example #22
Source File: analysisResultStateSlice.ts    From prism-frontend with MIT License 5 votes vote down vote up
requestAndStoreExposedPopulation = createAsyncThunk<
  AnalysisResult,
  ExposedPopulationDispatchParams,
  CreateAsyncThunkTypes
>('analysisResultState/requestAndStoreExposedPopulation', async params => {
  const { exposure, date, extent, statistic, wfsLayerId } = params;

  const { id, key } = exposure;

  const wfsLayer = LayerDefinitions[wfsLayerId] as WMSLayerProps;
  const populationLayer = LayerDefinitions[id] as WMSLayerProps;

  const wfsParams: WfsRequestParams = {
    url: `${wfsLayer.baseUrl}/ows`,
    layer_name: wfsLayer.serverLayerName,
    time: moment(date).format(DEFAULT_DATE_FORMAT),
    key,
  };

  const apiRequest = createAPIRequestParams(
    populationLayer,
    extent,
    date,
    wfsParams,
  );

  const apiFeatures = (await fetchApiData(
    ANALYSIS_API_URL,
    apiRequest,
  )) as Feature[];

  const { scale, offset } = populationLayer.wcsConfig ?? {
    scale: undefined,
    offset: undefined,
  };

  const features =
    !scale && !offset
      ? apiFeatures
      : apiFeatures.map(f =>
          scaleFeatureStat(f, scale || 1, offset || 0, statistic),
        );

  const collection: FeatureCollection = {
    type: 'FeatureCollection',
    features,
  };

  const groupBy = apiRequest.group_by;
  const legend = createLegendFromFeatureArray(features, statistic);
  const legendText = wfsLayer.title;

  return new ExposedPopulationResult(
    collection,
    statistic,
    legend,
    legendText,
    groupBy,
    key,
  );
})
Example #23
Source File: BoundaryDropdown.tsx    From prism-frontend with MIT License 5 votes vote down vote up
GotoBoundaryDropdown = () => {
  const map = useSelector(mapSelector);

  const [boundaries, setBoundaries] = useState<string[]>([]);

  const boundaryLayerData = useSelector(layerDataSelector(boundaryLayer.id)) as
    | LayerData<BoundaryLayerProps>
    | undefined;
  const { data } = boundaryLayerData || {};

  const {
    map: { latitude, longitude, zoom },
  } = appConfig;

  const { t } = useSafeTranslation();

  const styles = useStyles();

  if (!data || !map || !enableNavigationDropdown) {
    return null;
  }

  return (
    <div className={styles.dropdownMenu}>
      <CenterFocusWeak fontSize="small" className={styles.icon} />
      <ButtonStyleBoundaryDropdown
        selectedBoundaries={boundaries}
        selectAll={false}
        labelMessage={t('Go To')}
        className={styles.formControl}
        setSelectedBoundaries={(newSelectedBoundaries, appendMany) => {
          setBoundaries(() => {
            if (appendMany === true) {
              return newSelectedBoundaries;
            }

            return newSelectedBoundaries.slice(-1);
          });

          if (newSelectedBoundaries.length === 0) {
            map.flyTo({ center: { lng: longitude, lat: latitude }, zoom });

            return;
          }

          const geometries = data.features
            .filter(f =>
              newSelectedBoundaries.includes(
                f.properties && f.properties[boundaryLayer.adminCode],
              ),
            )
            .filter(f => f.geometry.type === 'MultiPolygon')
            .map(f => f.geometry as MultiPolygon);

          const bboxes = geometries.map(geom => {
            const turfObj = multiPolygon(geom.coordinates);
            const geomBbox = bbox(turfObj);

            return geomBbox;
          });

          const bboxPolygons = bboxes.map(box => bboxPolygon(box));
          const unionBbox = bboxPolygons.reduce((unionPolygon, polygon) => {
            const unionObj = union(unionPolygon, polygon);
            if (!unionObj) {
              return unionPolygon;
            }
            return unionObj as Feature<Polygon>;
          }, bboxPolygons[0]);

          map.fitBounds(bbox(unionBbox) as Extent, {
            padding: 30,
          });
        }}
      />
    </div>
  );
}
Example #24
Source File: mapObject.ts    From react-tutorials with MIT License 5 votes vote down vote up
setMapObject = (data: Array<Feature<Geometry | null>>): mapObject => ({
  mapFeatures: data,
})
Example #25
Source File: mapObject.ts    From react-tutorials with MIT License 5 votes vote down vote up
initMapObject = (): mapObject => ({
  mapFeatures: Array<Feature<null>>(),
})
Example #26
Source File: RoundWorldMap.tsx    From react-tutorials with MIT License 5 votes vote down vote up
RoundWorldMap = () => {
  const [geographies, setGeographies] = useState<[] | Array<Feature<Geometry | null>>>([])
  // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
  const [rotation, setRotation] = useState<number>(initRotation)

  useEffect(() => {
    fetch('/data/world-110m.json').then((response) => {
      if (response.status !== 200) {
        // eslint-disable-next-line no-console
        console.log(`Houston we have a problem: ${response.status}`)
        return
      }
      response.json().then((worldData) => {
        const mapFeatures: Array<Feature<Geometry | null>> = ((feature(worldData, worldData.objects.countries) as unknown) as FeatureCollection).features
        setGeographies(mapFeatures)
      })
    })
  }, [])

  const projection = geoOrthographic().scale(scale).translate([cx, cy]).rotate([rotation, 0])

  return (
    <svg width={scale * 3} height={scale * 3} viewBox="0 0 800 450">
      <g>
        <circle fill="#f2f2f2" cx={cx} cy={cy} r={scale} />
      </g>
      <g>
        {(geographies as []).map((d, i) => (
          <path
            key={`path-${uuid()}`}
            d={geoPath().projection(projection)(d) as string}
            fill={`rgba(38,50,56,${(1 / (geographies ? geographies.length : 0)) * i})`}
            stroke="aliceblue"
            strokeWidth={0.5}
          />
        ))}
      </g>
    </svg>
  )
}
Example #27
Source File: AircraftLayer.tsx    From react-flight-tracker with MIT License 4 votes vote down vote up
AircraftLayer: React.FC<Props> = (props) => {

  // Fields
  const contextName: string = 'AircraftLayer'

  // External hooks
  const styleTheme = useTheme();

  // States
  const [featureCollection, setFeatureCollection] = useState<FeatureCollection | undefined>(undefined);
  const [pathPredictions, setPathPredictions] = useState<Array<Feature<Point, GeoJsonProperties>>>([]);

  // Contexts
  const systemContext = useContext(SystemContext)
  const geospatialService = systemContext.getService<IGeospatialService>('GeospatialService');

  // Refs
  const pathPredictionSubscriptionRef = useRef<string>('');

  // Effects
  useEffect(() => {

    // Mount
    if (geospatialService) {

      // Get a register key for the subscription and save it as reference
      const registerKey = geospatialService.onPathPredictionUpdated(contextName, handlePathPredictionUpdated);
      pathPredictionSubscriptionRef.current = registerKey;
    }

    // Unmount
    return () => {

      if (geospatialService) {

        geospatialService.stopPathPrediction();

        // Get the register key from the reference to unsubscribe
        const registerKey = pathPredictionSubscriptionRef.current;
        geospatialService.offPathPredictionUpdated(registerKey);
      }
    }
  }, []);
  useEffect(() => {

    createFeatureCollection(pathPredictions).then((featureCollection) => {

      setFeatureCollection(featureCollection);

      if (!geospatialService)
        return;

      if (props.stateVectors.states.length > 1000) {
        geospatialService.stopPathPrediction();
      }
      else {
        geospatialService.restartPathPrediction(props.stateVectors);
      }
    })



  }, [props.stateVectors]);
  useEffect(() => {

    createFeatureCollection(pathPredictions).then((featureCollection) => {

      setFeatureCollection(featureCollection);
    })

  }, [pathPredictions]);

  const handlePathPredictionUpdated = (destinations: Array<Feature<Point, GeoJsonProperties>>) => {
    setPathPredictions(destinations);
  };

  const createFeatureCollection = (pathPredictions: Array<Feature<Point, GeoJsonProperties>>) => {

    return new Promise<FeatureCollection>((res, rej) => {

      var featureCollection: FeatureCollection = {
        type: 'FeatureCollection',
        features: []
      };

      for (var stateVector of props.stateVectors.states) {

        if (!stateVector.latitude) {
          continue;
        }

        if (!stateVector.longitude) {
          continue;
        }

        // Get the index
        const index = props.stateVectors.states.indexOf(stateVector);

        // Check for selection
        var isSelected = false;
        if (props.selectedAircraft)
          isSelected = stateVector.icao24 === props.selectedAircraft.icao24;

        // Get callsign
        const callsign = stateVector.callsign ? stateVector.callsign : stateVector.icao24;

        // Get altitude
        var altitude = stateVector.geo_altitude;
        if ((altitude === null) || (altitude < 0))
          altitude = stateVector.baro_altitude;
        if ((altitude === null) || (altitude < 0))
          altitude = 0;

        // Get velocity in km/h
        const velocity = stateVector.velocity ? (stateVector.velocity * 3.6) : -1;

        // Get true track
        const trueTrack = stateVector.true_track ? stateVector.true_track : 0.0;

        // Get vertical rate
        const verticalRate = stateVector.vertical_rate ? stateVector.vertical_rate : 0.0;

        // Get is on ground
        const isOnGround = stateVector.on_ground;

        // Claculate color
        var color = getColor(altitude);
        if (isOnGround)
          color = styleTheme.palette.text.secondary;
        if (isSelected)
          color = styleTheme.palette.primary.main;

        var properties: GeoJsonProperties = {
          ['iconName']: getIconName(isOnGround, verticalRate, altitude, trueTrack),
          ['rotation']: getRotation(trueTrack, verticalRate, altitude),
          ['color']: color,
          ['isSelected']: isSelected,
          ['icao24']: stateVector.icao24,
          ['callsign']: callsign,
          ['altitude']: getFormattedValue(altitude, 1) + " m",
          ['velocity']: getFormattedValue(velocity, 1) + " km/h"
        }

        // Setup WGS84 coordinates
        var position: Position = [stateVector.longitude, stateVector.latitude];

        if (pathPredictions.length > 0) {

          const feature = pathPredictions.find(feature => feature.properties !== null && feature.properties['icao24']! === stateVector.icao24);
          if (feature)
            position = feature.geometry.coordinates;
        }

        var point: Point = {
          type: 'Point',
          coordinates: position
        };

        var feature: Feature<Point, GeoJsonProperties> = {
          type: 'Feature',
          id: `${index}.${stateVector.icao24}`,
          geometry: point,
          properties: properties
        }

        featureCollection.features.push(feature);
      }

      res(featureCollection);
    });

  };

  const getText = (): string | Expression | StyleFunction => {

    var text: string | Expression | StyleFunction = '';
    const simpleText = ["get", "callsign"] as Expression
    const detailedText = ['format',
      ["get", "callsign"], { "font-scale": 1.0 },
      "\n", {},
      ["get", "altitude"], { "font-scale": 0.75, "text-color": styleTheme.palette.text.primary },
      "\n", {},
      ["get", "velocity"], { "font-scale": 0.75, "text-color": styleTheme.palette.text.primary }
    ] as StyleFunction;

    if (props.zoom && props.zoom > 7)
      text = simpleText;
    if (props.zoom && props.zoom > 9)
      text = detailedText;

    return text;
  };

  const getSymbolLayout = () => {

    var showText = false;
    if (props.zoom && props.zoom > 7)
      showText = true;

    var isconSize = 1.0;
    if (props.zoom && props.zoom > 7)
      isconSize = 1.3;
    if (props.zoom && props.zoom > 9)
      isconSize = 1.6;

    const symbolLayout: SymbolLayout = {
      "icon-image": ["get", "iconName"],
      "icon-allow-overlap": true,
      "icon-rotate": ["get", "rotation"],
      "icon-size": isconSize,
      "text-field": showText ? getText() : '',
      "text-optional": true,
      "text-allow-overlap": true,
      "text-anchor": showText ? 'top' : 'center',
      "text-offset": showText ? [0, 1] : [0, 0]
    };

    return symbolLayout;
  };

  const getSymbolPaint = () => {

    var symbolPaint: SymbolPaint = {
      "icon-color": ["get", "color"],
      "text-color": ["get", "color"],
      "text-halo-width": 2,
      "text-halo-color": styleTheme.palette.background.default,
      "text-halo-blur": 2
    };

    return symbolPaint;
  };

  if (!props.stateVectors.states)
    return null;

  return (

    <Source
      type="geojson"
      data={featureCollection}>

      <Layer
        id={aircraftLayerId}
        type='symbol'
        source='geojson'
        layout={getSymbolLayout()}
        paint={getSymbolPaint()} />
    </Source>
  )
}
Example #28
Source File: FlightMap.tsx    From react-flight-tracker with MIT License 4 votes vote down vote up
FlightMap: React.FC<Props> = (props) => {

  // External hooks
  const styleTheme = useTheme();

  // Contexts
  const systemContext = useContext(SystemContext);

  const getDefaultViewState = () => {

    const defaultViewState: ViewState = {
      latitude: Constants.DEFAULT_LATITUDE,
      longitude: Constants.DEFAULT_LONGITUDE,
      zoom: Constants.DEFAULT_ZOOM,
      bearing: 0,
      pitch: 0,
      padding: {
        top: 0,
        bottom: 0,
        left: 0,
        right: 0
      }
    };

    return defaultViewState;
  };

  // States
  const [viewState, setViewState] = useState<ViewState>(getDefaultViewState());

  // Refs
  const mapRef = useRef<MapRef | null>(null);

  // Effects
  useEffect(() => {

    // Mount

    // Unmount
    return () => {
    }
  }, []);
  useEffect(() => {

    const mapGeoBounds = getMapGeoBounds();
    if (props.onMapChange)
      props.onMapChange(viewState, mapGeoBounds);

  }, [mapRef.current]);

  const getMapGeoBounds = () => {

    var mapGeoBounds: IMapGeoBounds = {
      northernLatitude: 0.0,
      easternLongitude: 0.0,
      southernLatitude: 0.0,
      westernLongitude: 0.0
    }

    if (mapRef.current) {

      const map = mapRef.current.getMap();
      const mapBounds = map.getBounds();
      mapGeoBounds.northernLatitude = mapBounds.getNorthEast().lat;
      mapGeoBounds.easternLongitude = mapBounds.getNorthEast().lng;
      mapGeoBounds.southernLatitude = mapBounds.getSouthWest().lat;
      mapGeoBounds.westernLongitude = mapBounds.getSouthWest().lng;
    }

    return mapGeoBounds;
  };

  const addMapSources = (map: Map) => {

    svgToImageAsync(FlightIcon, 24, 24).then(image => {

      if (!map.hasImage('flight-icon'))
        map.addImage('flight-icon', image, { sdf: true });
    });
    svgToImageAsync(FlightLandIcon, 24, 24).then(image => {

      if (!map.hasImage('flight-land-icon'))
        map.addImage('flight-land-icon', image, { sdf: true });
    });
    svgToImageAsync(FlightLandFlippedIcon, 24, 24).then(image => {

      if (!map.hasImage('flight-land-flipped-icon'))
        map.addImage('flight-land-flipped-icon', image, { sdf: true });
    });
    svgToImageAsync(FlightTakeoffIcon, 24, 24).then(image => {

      if (!map.hasImage('flight-takeoff-icon'))
        map.addImage('flight-takeoff-icon', image, { sdf: true });
    });
    svgToImageAsync(FlightTakeoffFlippedIcon, 24, 24).then(image => {

      if (!map.hasImage('flight-takeoff-flipped-icon'))
        map.addImage('flight-takeoff-flipped-icon', image, { sdf: true });
    });
  };

  const handleLoad = (e: MapboxEvent<undefined>) => {

    const map = e.target;
    if (map == undefined)
      return;

    addMapSources(map);
  };

  const handleStyleData = (e: MapStyleDataEvent) => {

    const map = e.target;
    if (map == undefined)
      return;

    addMapSources(map);
  };

  const handleClick = (e: MapLayerMouseEvent) => {

    if (e.features == undefined || e.features.length <= 0)
      return;

    const selectedFeature = e.features[0] as Feature;
    if (selectedFeature.properties) {

      const icao24 = selectedFeature.properties['icao24'] as string;
      if (icao24)
        if (props.onTrackAircraft)
          props.onTrackAircraft(icao24);
    }
  };

  const handleMove = (e: ViewStateChangeEvent) => {

    setViewState(e.viewState);

    const mapGeoBounds = getMapGeoBounds();
    if (props.onMapChange)
      props.onMapChange(viewState, mapGeoBounds);
  };

  // Helpers
  const defaultMapSettings = {
    dragPan: true,
    dragRotate: false,
    scrollZoom: true,
    keyboard: true,
    doubleClickZoom: true,
    minZoom: 0,
    maxZoom: 20,
    minPitch: 0,
    maxPitch: 85
  }

  const showDataOverlayOnMap = systemContext.getSetting(SettingKeys.ShowDataOverlayOnMap);
  const showLogOverlayOnMap = systemContext.getSetting(SettingKeys.ShowLogOverlayOnMap);

  return (

    <ReactMap
      ref={mapRef}
      style={{
        width: '100%',
        height: '100%'
      }}
      {...viewState}
      {...defaultMapSettings}
      interactiveLayerIds={[
        aircraftLayerId
      ]}
      mapStyle={styleTheme.map.style}
      mapboxAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
      onLoad={handleLoad}
      onClick={handleClick}
      onMove={handleMove}
      onStyleData={handleStyleData}>

      <FullscreenControl
        position='bottom-right' />

      <NavigationControl
        position='bottom-right' />

      {showDataOverlayOnMap &&
        <Box
          sx={{
            position: 'absolute',
            bottom: 48,
            right: 50
          }}>
          <DataOverlay
            stateVectors={props.stateVectors} />
        </Box>
      }

      {showLogOverlayOnMap &&
        <Box
          sx={{
            position: 'absolute',
            bottom: 186,
            right: 50
          }}>
          <LogOverlay />
        </Box>
      }

      {props.selectedAircraft &&
        <Box
          sx={{
            position: 'absolute',
            bottom: 48,
            left: 0,
            padding: '10px'
          }}>

          <AircraftInfoOverlay
            selectedAircraft={props.selectedAircraft}
            onRelease={props.onReleaseTrack} />
        </Box>
      }

      <AircraftLayer
        stateVectors={props.stateVectors}
        zoom={viewState.zoom}
        selectedAircraft={props.selectedAircraft} />

    </ReactMap>
  );
}
Example #29
Source File: RotatingRoundWorldMapWithCoordinates.tsx    From react-tutorials with MIT License 4 votes vote down vote up
RotatingRoundWorldMapWithCoordinates = () => {
  const [geographies, setGeographies] = useState<[] | Array<Feature<Geometry | null>>>([])
  const [rotation, setRotation] = useState<number>(initRotation)
  const [isRotate, setIsRotate] = useState<Boolean>(false)

  useEffect(() => {
    fetch('/data/world-110m.json').then((response) => {
      if (response.status !== 200) {
        // eslint-disable-next-line no-console
        console.log(`Houston we have a problem: ${response.status}`)
        return
      }
      response.json().then((worldData) => {
        const mapFeatures: Array<Feature<Geometry | null>> = ((feature(worldData, worldData.objects.countries) as unknown) as FeatureCollection).features
        setGeographies(mapFeatures)
      })
    })
  }, [])

  // geoEqualEarth
  // geoOrthographic
  const projection = geoOrthographic().scale(scale).translate([cx, cy]).rotate([rotation, 0])

  AnimationFrame(() => {
    if (isRotate) {
      let newRotation = rotation
      if (rotation >= 360) {
        newRotation = rotation - 360
      }
      setRotation(newRotation + 0.2)
      // console.log(`rotation: ${  rotation}`)
    }
  })

  function returnProjectionValueWhenValid(point: [number, number], index: number) {
    const retVal: [number, number] | null = projection(point)
    if (retVal?.length) {
      return retVal[index]
    }
    return 0
  }

  const handleMarkerClick = (i: number) => {
    // eslint-disable-next-line no-alert
    alert(`Marker: ${JSON.stringify(data[i])}`)
  }

  return (
    <>
      <Button
        size="medium"
        color="primary"
        startIcon={<PlayCircleFilledWhiteIcon />}
        onClick={() => {
          setIsRotate(true)
        }}
      />
      <svg width={scale * 3} height={scale * 3} viewBox="0 0 800 450">
        <g>
          <circle fill="#f2f2f2" cx={cx} cy={cy} r={scale} />
        </g>
        <g>
          {(geographies as []).map((d, i) => (
            <path
              key={`path-${uuid()}`}
              d={geoPath().projection(projection)(d) as string}
              fill={`rgba(38,50,56,${(1 / (geographies ? geographies.length : 0)) * i})`}
              stroke="aliceblue"
              strokeWidth={0.5}
            />
          ))}
        </g>
        <g>
          {data.map((d, i) => (
            <circle
              key={`marker-${uuid()}`}
              cx={returnProjectionValueWhenValid(d.coordinates, 0)}
              cy={returnProjectionValueWhenValid(d.coordinates, 1)}
              r={5}
              fill="#E91E63"
              stroke="#FFFFFF"
              onClick={() => handleMarkerClick(i)}
              onMouseEnter={() => setIsRotate(false)}
            />
          ))}
        </g>
      </svg>
    </>
  )
}