7.3.292-stable Switch to dev

<gui-map />

Maplibregl

This component relies on maplibre-gl in order to work. This library is not vendored with @greycat/web, it is your responsibility to define maplibregl globally prior to initializing the SDK:

import '@greycat/web';
import maplibregl from 'maplibre-gl';

await gc.sdk.init({ maplibregl }); // this tells GreyCat to also load the components that rely on `maplibregl`

Markers example

Display markers on a map from a sampled nodeGeo that uses cities.csv

const el = document.createElement('div');
el.style.height = '600px';
const markers = document.createElement('gui-map-markers');
const map = document.createElement('gui-map');
map.options = {
  style: 'style.json',
  center: gc.core.geo.fromLatLng(49.6181, 6.162),
  zoom: 3,
};
el.appendChild(map);
map.appendChild(markers);

const root = await gc.$.default.root();
const nCities = root['project::cities'];
map.ready.then((m) => {
  m.on('zoomend', updateCities);
  m.on('dragend', updateCities);
  async function updateCities() {
    const bounds = m.getBounds();
    const tCities = await gc.core.nodeGeo.sample(
      [nCities],
      gc.core.geo.fromLatLng(bounds.getSouthWest()),
      gc.core.geo.fromLatLng(bounds.getNorthEast()),
      1000,
      gc.core.SamplingMode.dense,
    );
    const cities = [];
    for (const row of tCities) {
      cities.push({ geo: row[0], data: row[1] });
    }
    markers.value = cities;
  }
  updateCities();
});
var cities: nodeGeo<City>;

type City {
  country: String;
  name: String;
  location: geo;
  population: int;
  type: CapitalType;
}

enum CapitalType {
  Others,
  "Administrative Capital",
  "Seat of Government",
  Capital,
  "Legislative Capital",
  "Economic Capital",
}

fn import() {
  if (cities.size() != 0) {
    return;
  }
  var reader = CsvReader<City> {
    path: "csv/cities.csv",
    format: CsvFormat {
      header_lines: 1,
    },
  };

  while (reader.can_read()) {
    var record = reader.read();
    cities.set(record.location, record);
  }
}

Heatmap example

Displays earthquakes as a heatmap based on there magnitude. The data is available at earthquakes_4.5_month.csv.

const el = document.createElement('div');
el.style.position = 'relative';
el.style.height = '600px';

// Fetch data from GreyCat
const earthquakes = await gc.project.earthquakes();
// Convert the array to a GeoJSON.FeatureCollection
const geojson = earthquakes.toFeatureCollection((e) => ({
  type: 'Point',
  coordinates: [e.location.lat, e.location.lng],
}));

const drawer = document.createElement('sl-drawer');
drawer.label = 'Earthquake';
drawer.contained = true;
drawer.placement = 'start';
drawer.style.position = 'absolute';
drawer.style.setProperty('--width', '400px');

const hoveredDisplay = document.createElement('gui-object');
let hoveredId;

const footer = document.createElement('sl-button');
footer.slot = 'footer';
footer.variant = 'primary';
footer.onclick = () => drawer.hide();
footer.textContent = 'Close';

drawer.append(hoveredDisplay, footer);

const map = document.createElement('gui-map');
map.options = {
  style: 'style.json',
  center: gc.core.geo.fromLatLng(49.6181, 6.162),
  zoom: 3,
};
map.ready.then((m) => {
  m.addSource('earthquakes', { type: 'geojson', data: geojson });

  m.addLayer({
    'id': 'earthquakes-heat',
    'type': 'heatmap',
    'source': 'earthquakes',
    'maxzoom': 9,
    'paint': {
      // Increase the heatmap weight based on frequency and property magnitude
      'heatmap-weight': ['interpolate', ['linear'], ['get', 'mag'], 0, 0, 6, 1],
      // Increase the heatmap color weight weight by zoom level
      // heatmap-intensity is a multiplier on top of heatmap-weight
      'heatmap-intensity': ['interpolate', ['linear'], ['zoom'], 0, 1, 9, 3],
      // Color ramp for heatmap.  Domain is 0 (low) to 1 (high).
      // Begin color ramp at 0-stop with a 0-transparency color
      // to create a blur-like effect.
      'heatmap-color': [
        'interpolate',
        ['linear'],
        ['heatmap-density'],
        0, 'rgba(33,102,172,0)',
        0.2, 'rgb(103,169,207)',
        0.4, 'rgb(209,229,240)',
        0.6, 'rgb(253,219,199)',
        0.8, 'rgb(239,138,98)',
        1, 'rgb(178,24,43)'
      ],
      // Adjust the heatmap radius by zoom level
      'heatmap-radius': ['interpolate', ['linear'], ['zoom'], 0, 2, 9, 20],
      // Transition from heatmap to circle layer by zoom level
      'heatmap-opacity': ['interpolate', ['linear'], ['zoom'], 7, 1, 9, 0]
    }
  });

  m.addLayer({
    'id': 'earthquakes-point',
    'type': 'circle',
    'source': 'earthquakes',
    'minzoom': 7,
    'paint': {
      // Size circle radius by earthquake magnitude and zoom level
      'circle-radius': [
        'interpolate',
        ['linear'],
        ['zoom'],
        7,
        ['interpolate', ['linear'], ['get', 'mag'], 1, 1, 6, 4],
        16,
        ['interpolate', ['linear'], ['get', 'mag'], 1, 5, 6, 50]
      ],
      // Color circle by earthquake magnitude
      'circle-color': [
        'interpolate',
        ['linear'],
        ['get', 'mag'],
        1, 'rgba(33,102,172,0)',
        2, 'rgb(103,169,207)',
        3, 'rgb(209,229,240)',
        4, 'rgb(253,219,199)',
        5, 'rgb(239,138,98)',
        6, 'rgb(178,24,43)'
      ],
      // Update the circle stroke color based on the hovered state
      'circle-stroke-color': ['case', ['boolean', ['feature-state', 'hover'], false], 'rgb(192,248,95)', 'white'],
      'circle-stroke-width': ['case', ['boolean', ['feature-state', 'hover'], false], 3, 1],
      // Transition from heatmap to circle layer by zoom level
      'circle-opacity': ['interpolate', ['linear'], ['zoom'], 7, 0, 8, 1]
    }
  });
  
  m.on('mousemove', 'earthquakes-point', (e) => {
    if (!e.features || e.features.length === 0 || hoveredId === e.features[0].id) {
      return;
    }
    if (hoveredId) {
      m.setFeatureState({ source: 'earthquakes', id: hoveredId }, { hover: false });
    }
    hoveredId = e.features[0].id;
    m.setFeatureState({ source: 'earthquakes', id: hoveredId }, { hover: true });
    hoveredDisplay.value = earthquakes[hoveredId];
    drawer.show();
  });
});

el.append(map, drawer);
var earthquakes_by_geo: nodeGeo<Earthquake>;
var earthquakes_by_time: nodeTime<Earthquake>;

type Earthquake {
  time: time;
  location: geo;
  depth: float;
  mag: float;
  magType: MagType;
  nst: int?;
  gap: int?;
  dmin: float?;
  rms: float;
  net: Net;
  id: String;
  updated: time;
  place: String;
  horizontalError: float?;
  depthError: float;
  magError: float?;
  magNst: int?;
  magSource: MagSource;
}

@volatile
private type Record {
  /// column=0
  @format("%Y-%m-%dT%H:%M:%S%z")
  time: time;
  /// column=1, min=-61.8842, max=83.8394, avg=22.4896408333
  latitude: float;
  /// column=2, min=-179.369, max=179.8605, avg=83.5534406667
  longitude: float;
  /// column=3, min=7.466, max=639.511, avg=55.0781866667
  depth: float;
  /// column=4, min=4.5, max=7.8, avg=4.8468333333
  mag: float;
  /// column=5
  magType: MagType;
  /// column=6, min=9, max=287, avg=63.9296482412
  nst: int?;
  /// column=7, min=20, max=263, avg=108.076599665
  gap: int?;
  /// column=8, min=0.1, max=31.484, avg=2.6537839196
  dmin: float?;
  /// column=9, min=0.32, max=1.55, avg=0.8291103333
  rms: float;
  /// column=10
  net: Net;
  /// column=11
  id: String;
  /// column=12
  @format("%Y-%m-%dT%H:%M:%S%z")
  updated: time;
  /// column=13
  place: String;
  /// column=14
  type: Type;
  /// column=15, min=2.88, max=17.47, avg=8.7943456376
  horizontalError: float?;
  /// column=16, min=0.972, max=22.5, avg=4.4283683333
  depthError: float;
  /// column=17, min=0.02, max=0.205, avg=0.0727785235
  magError: float?;
  /// column=18, min=7, max=818, avg=101.1375838926
  magNst: int?;
  /// column=19
  status: Status;
  /// column=20
  locationSource: LocationSource;
  /// column=21
  magSource: MagSource;
}

enum MagType {
  mww,
  ml,
  mw,
  mwr,
  mb,
}

enum Net {
  ak,
  us,
  nn,
}

@volatile
private enum Type {
  earthquake,
}

@volatile
private enum Status {
  reviewed,
}

@volatile
private enum LocationSource {
  ak,
  us,
  nn,
}

@volatile
private enum MagSource {
  ak,
  us,
  nn,
}

fn import_earthquakes() {
    if (earthquakes_by_geo.size() > 0) {
        return;
    }

    var reader = CsvReader<Record> {
        path: "web-components/gui-map/earthquakes_4.5_month.csv",
        format: CsvFormat {
            header_lines: 1,
        },
    };

    var record: Record;
    while (reader.can_read()) {
        record = reader.read();
        var earthquake = Earthquake {
            location: geo { record.latitude, record.longitude },
            time: record.time,
            depth: record.depth,
            depthError: record.depthError,
            mag: record.mag,
            magType: record.magType,
            nst: record.nst,
            gap: record.gap,
            dmin: record.dmin,
            rms: record.rms,
            net: record.net,
            id: record.id,
            updated: record.updated,
            place: record.place,
            magError: record.magError,
            magNst: record.magNst,
            magSource: record.magSource,
        };
        earthquakes_by_geo.set(earthquake.location, clone(earthquake));
        earthquakes_by_time.setAt(earthquake.time, earthquake);
    }
    info("Imported ${earthquakes_by_geo.size()} eartquakes from ${earthquakes_by_time.firstTime()} to ${earthquakes_by_time.lastTime()}");
}

@expose
fn earthquakes(): Array<Earthquake> {
    var arr = Array<Earthquake> {};
    arr.set_capacity(earthquakes_by_time.size());
    for (_, e in earthquakes_by_time) {
        arr.add(e);
    }
    return arr;
}