Search

Interacting with Leaflet

Advanced

Enhance your charts with a map background by Leaflet.

Interacting with Leaflet
View live example →

Click on a state to see its flights.

To customize the map, access the underlying Leaflet API through map.leaflet in the options prop.

You can also set map tiles through the map.tiles property.

See also

/* global L */
import React, { useRef, useState } from "react";
import { createRoot } from "react-dom/client";

import has from "lodash/has";
import mapValues from "lodash/mapValues";
import pickBy from "lodash/pickBy";
// 'point-in-polygon-hao' is used to identify if an airport coordinates (point) is within the selected
// state boundaries (polygon).
import pointInPolygon from "point-in-polygon-hao";
import { Chart } from "regraph";
import { neighbors } from "regraph/analysis";

import {
  data,
  geoJSON,
  regionBgStyle,
  regionHoverStyle,
  regionSelectStyle,
} from "./data";

import "leaflet/dist/leaflet";
import "leaflet/dist/leaflet.css";
import "@ci/theme/rg/css/button.css";
import "@ci/theme/rg/css/layout.css";

function isNode(item) {
  return !has(item, "id1");
}

function isPointInStateGeometry(point, { type, coordinates }) {
  if (type === "Polygon") return pointInPolygon(point, coordinates);
  if (type === "MultiPolygon")
    return coordinates.some((polygon) => pointInPolygon(point, polygon));
  return false;
}

function getNodesInRegion(items, selectedRegion) {
  // If a region is selected, only include nodes within the bounds
  const regionBounds = selectedRegion.getBounds();
  return pickBy(items, (item) => {
    // Check whether node is roughly in the right area
    if (
      isNode(item) &&
      regionBounds.contains([item.coordinates.lat, item.coordinates.lng])
    ) {
      return isPointInStateGeometry(
        [item.coordinates.lng, item.coordinates.lat],
        selectedRegion.toGeoJSON().geometry,
      );
    }
    return false;
  });
}

export const Demo = () => <LeafletLayers items={data()} />;

function LeafletLayers(props) {
  const { items } = props;
  const stopLeafletEventHandlers = useRef(true);

  const [state, setState] = useState({
    selectedRegion: null,
    foregroundItems: items,
  });

  const regionsMap = React.useRef(
    L.geoJson(geoJSON, {
      style: regionBgStyle,
    }),
  );

  const resetSelectedRegionStyle = (selectedRegion) => {
    if (selectedRegion) {
      regionsMap.current.resetStyle(selectedRegion);
    }
  };

  const selectRegion = React.useCallback(
    async (region) => {
      const { selectedRegion } = state;
      if (region === selectedRegion) {
        return;
      }
      if (region) {
        region.setStyle(regionSelectStyle);
      }
      // When regions are selected, highlight the region's airports and their direct connections
      const nodesInRegion = getNodesInRegion(items, region);
      // show only direct neighbors of nodes
      const neighborNodes = await neighbors(items, nodesInRegion);
      setState((current) => {
        // Set the highlight color on the region
        resetSelectedRegionStyle(current.selectedRegion);
        return {
          selectedRegion: region,
          foregroundItems: { ...nodesInRegion, ...neighborNodes },
        };
      });
    },
    [state, items],
  );

  // The region's onClick handler: called after the chart's onClick,
  // but before the global Leaflet onClick handler
  const handleLeafletRegionClick = React.useCallback(
    (e) => {
      // Prevent the global Leaflet click handler from handling this event if a region was clicked
      L.DomEvent.stop(e);
      if (stopLeafletEventHandlers.current) {
        return;
      }
      selectRegion(e.target);
    },
    [selectRegion],
  );

  // highlight the border on mouseover
  const handleLeafletRegionMouseOver = React.useCallback(
    (e) => {
      const { selectedRegion } = state;
      const layer = e.target;
      if (
        !selectedRegion ||
        e.target.feature.properties.STATE !==
          selectedRegion.feature.properties.STATE
      ) {
        layer.setStyle(regionHoverStyle);
      }
    },
    [state],
  );

  // on mouse out, we restore the original style
  const handleLeafletRegionMouseOut = React.useCallback(
    (e) => {
      const { selectedRegion } = state;
      if (
        !selectedRegion ||
        e.target.feature.properties.STATE !==
          selectedRegion.feature.properties.STATE
      ) {
        regionsMap.current.resetStyle(e.target);
      }
    },
    [state],
  );

  React.useEffect(() => {
    const currentRegionsMap = regionsMap.current;
    currentRegionsMap.eachLayer((layer) => {
      layer.on({
        click: handleLeafletRegionClick,
        mouseover: handleLeafletRegionMouseOver,
        mouseout: handleLeafletRegionMouseOut,
      });
    });

    return () => {
      currentRegionsMap.eachLayer((layer) => layer.off());
    };
  }, [
    handleLeafletRegionClick,
    handleLeafletRegionMouseOver,
    handleLeafletRegionMouseOut,
  ]);

  const selectNode = async (id) => {
    let itemsToForeground;
    if (!id) {
      itemsToForeground = items;
    } else {
      // show only direct neighbors of nodes
      itemsToForeground = await neighbors(items, { [id]: true });
      itemsToForeground[id] = true;
    }

    setState((current) => {
      resetSelectedRegionStyle(current.selectedRegion);
      return {
        selectedRegion: null,
        foregroundItems: itemsToForeground,
      };
    });
  };

  // Clicks on the chart are handled by multiple listeners.
  //
  // 1. The chart's onClick handler
  // 2. The region's onClick handler, if the click was within a defined region
  // 3. The global Leaflet onClick handler

  // The chart's onClick handler: called before any of Leaflet's click handlers
  const handleChartClick = ({ id }) => {
    // Prevent Leaflet event handlers from doing anything if a node has been clicked
    stopLeafletEventHandlers.current = id != null;
    if (id != null) {
      selectNode(id);
    }
  };

  // The global Leaflet onClick handler: called whenever the Leaflet map is clicked,
  // unless the event was intercepted previously
  const handleLeafletMapClick = () => {
    if (stopLeafletEventHandlers.current) {
      return;
    }
    selectNode(null);
  };

  const handleChartChange = (change) => {
    const { leaflet } = change;
    // The Leaflet property is set to the Leaflet map object when the map is shown
    if (leaflet) {
      leaflet.on("click", handleLeafletMapClick);
      regionsMap.current.addTo(leaflet);
    }
  };

  const styledItems = () => {
    const { foregroundItems } = state;
    return mapValues(items, (item, id) => ({
      ...item,
      fade: !foregroundItems[id],
    }));
  };

  return (
    <div className="story">
      <div className="chart-wrapper">
        <Chart
          items={styledItems()}
          map
          options={{
            map: {
              tiles: {
                url: "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
                attribution:
                  '&copy; <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions" target="_blank">CartoDB</a>',
              },
              leaflet: {
                maxZoom: 10,
              },
            },
          }}
          animation={{ animate: false }}
          onChange={handleChartChange}
          onClick={handleChartClick}
        />
      </div>
    </div>
  );
}

const root = createRoot(document.getElementById("regraph"));
root.render(<Demo />);
import { style } from "@ci/theme/rg/js/storyStyles";

function data() {
  return {
    HNL: {
      label: [{ text: "HNL", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 21.318681,
        lng: -157.922428,
      },
    },
    OGG: {
      label: [{ text: "OGG", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 20.89865,
        lng: -156.430458,
      },
    },
    DAL: {
      label: [{ text: "DAL", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 32.847111,
        lng: -96.851778,
      },
    },
    HOU: {
      label: [{ text: "HOU", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 29.645419,
        lng: -95.278889,
      },
    },
    LAX: {
      label: [{ text: "LAX", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 33.942536,
        lng: -118.408075,
      },
    },
    SAN: {
      label: [{ text: "SAN", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 32.733556,
        lng: -117.189667,
      },
    },
    KOA: {
      label: [{ text: "KOA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 19.738767,
        lng: -156.045631,
      },
    },
    LIH: {
      label: [{ text: "LIH", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 21.975983,
        lng: -159.338958,
      },
    },
    DFW: {
      label: [{ text: "DFW", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 32.896828,
        lng: -97.037997,
      },
    },
    ORD: {
      label: [{ text: "ORD", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 41.978603,
        lng: -87.904842,
      },
    },
    ATL: {
      label: [{ text: "ATL", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 33.636719,
        lng: -84.428067,
      },
    },
    LGA: {
      label: [{ text: "LGA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 40.777245,
        lng: -73.872608,
      },
    },
    MCO: {
      label: [{ text: "MCO", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 28.429394,
        lng: -81.308994,
      },
    },
    MKE: {
      label: [{ text: "MKE", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 42.947222,
        lng: -87.896583,
      },
    },
    SAT: {
      label: [{ text: "SAT", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 29.533694,
        lng: -98.469778,
      },
    },
    ANC: {
      label: [{ text: "ANC", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 61.174361,
        lng: -149.996361,
      },
    },
    SEA: {
      label: [{ text: "SEA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 47.449,
        lng: -122.309306,
      },
    },
    AUS: {
      label: [{ text: "AUS", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 30.194528,
        lng: -97.669889,
      },
    },
    ITO: {
      label: [{ text: "ITO", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 19.721375,
        lng: -155.048469,
      },
    },
    BOS: {
      label: [{ text: "BOS", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 42.364347,
        lng: -71.005181,
      },
    },
    PHL: {
      label: [{ text: "PHL", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 39.871944,
        lng: -75.241139,
      },
    },
    FLL: {
      label: [{ text: "FLL", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 26.072583,
        lng: -80.15275,
      },
    },
    DCA: {
      label: [{ text: "DCA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 38.852083,
        lng: -77.037722,
      },
    },
    SFO: {
      label: [{ text: "SFO", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 37.618972,
        lng: -122.374889,
      },
    },
    TPA: {
      label: [{ text: "TPA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 27.975472,
        lng: -82.53325,
      },
    },
    EWR: {
      label: [{ text: "EWR", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 40.6925,
        lng: -74.168667,
      },
    },
    OAK: {
      label: [{ text: "OAK", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 37.721278,
        lng: -122.220722,
      },
    },
    IAH: {
      label: [{ text: "IAH", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 29.984433,
        lng: -95.341442,
      },
    },
    JFK: {
      label: [{ text: "JFK", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 40.639751,
        lng: -73.778925,
      },
    },
    MIA: {
      label: [{ text: "MIA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 25.79325,
        lng: -80.290556,
      },
    },
    BUR: {
      label: [{ text: "BUR", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 34.200667,
        lng: -118.358667,
      },
    },
    LAS: {
      label: [{ text: "LAS", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 36.080056,
        lng: -115.15225,
      },
    },
    JAX: {
      label: [{ text: "JAX", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 30.494056,
        lng: -81.687861,
      },
    },
    RDU: {
      label: [{ text: "RDU", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 35.877639,
        lng: -78.787472,
      },
    },
    SMF: {
      label: [{ text: "SMF", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 38.695417,
        lng: -121.590778,
      },
    },
    DEN: {
      label: [{ text: "DEN", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 39.861656,
        lng: -104.673178,
      },
    },
    MSP: {
      label: [{ text: "MSP", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 44.881956,
        lng: -93.221767,
      },
    },
    SJC: {
      label: [{ text: "SJC", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 37.3626,
        lng: -121.929022,
      },
    },
    BWI: {
      label: [{ text: "BWI", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 39.175361,
        lng: -76.668333,
      },
    },
    PHX: {
      label: [{ text: "PHX", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 33.434278,
        lng: -112.011583,
      },
    },
    MSY: {
      label: [{ text: "MSY", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 29.993389,
        lng: -90.258028,
      },
    },
    CLT: {
      label: [{ text: "CLT", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 35.214,
        lng: -80.943139,
      },
    },
    DTW: {
      label: [{ text: "DTW", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 42.212444,
        lng: -83.353389,
      },
    },
    RNO: {
      label: [{ text: "RNO", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 39.499108,
        lng: -119.768108,
      },
    },
    PBI: {
      label: [{ text: "PBI", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 26.683161,
        lng: -80.095589,
      },
    },
    SNA: {
      label: [{ text: "SNA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 33.675667,
        lng: -117.868222,
      },
    },
    CHS: {
      label: [{ text: "CHS", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 32.898647,
        lng: -80.040528,
      },
    },
    BNA: {
      label: [{ text: "BNA", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 36.124472,
        lng: -86.678194,
      },
    },
    MCI: {
      label: [{ text: "MCI", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 39.297606,
        lng: -94.713905,
      },
    },
    MDW: {
      label: [{ text: "MDW", bold: true, position: "e", fontSize: 40 }],
      ...style.primary2,
      size: 0.35,
      coordinates: {
        lat: 41.785972,
        lng: -87.752417,
      },
    },
    "HNL-OGG-HA": {
      id1: "HNL",
      id2: "OGG",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "HA", bold: true, color: "#115967" },
      color: "#115967",
      width: 10,
    },
    "DAL-HOU-WN": {
      id1: "DAL",
      id2: "HOU",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 8,
    },
    "LAX-SAN-OO": {
      id1: "LAX",
      id2: "SAN",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "OO", bold: true, color: "#8263a0" },
      color: "#8263a0",
      width: 8,
    },
    "HNL-KOA-HA": {
      id1: "HNL",
      id2: "KOA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "HA", bold: true, color: "#115967" },
      color: "#115967",
      width: 6,
    },
    "HNL-LIH-HA": {
      id1: "HNL",
      id2: "LIH",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "HA", bold: true, color: "#115967" },
      color: "#115967",
      width: 6,
    },
    "DFW-LAX-AA": {
      id1: "DFW",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 6,
    },
    "DFW-ORD-AA": {
      id1: "DFW",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 5,
    },
    "ATL-LGA-DL": {
      id1: "ATL",
      id2: "LGA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 5,
    },
    "ATL-MCO-DL": {
      id1: "ATL",
      id2: "MCO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 5,
    },
    "LGA-ORD-AA": {
      id1: "LGA",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 5,
    },
    "MKE-ORD-OO": {
      id1: "MKE",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "OO", bold: true, color: "#8263a0" },
      color: "#8263a0",
      width: 5,
    },
    "DFW-SAT-AA": {
      id1: "DFW",
      id2: "SAT",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 5,
    },
    "ANC-SEA-AS": {
      id1: "ANC",
      id2: "SEA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AS", bold: true, color: "#1f405f" },
      color: "#1f405f",
      width: 4,
    },
    "AUS-DFW-AA": {
      id1: "AUS",
      id2: "DFW",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 4,
    },
    "HNL-ITO-HA": {
      id1: "HNL",
      id2: "ITO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "HA", bold: true, color: "#115967" },
      color: "#115967",
      width: 4,
    },
    "BOS-PHL-US": {
      id1: "BOS",
      id2: "PHL",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "US", bold: true, color: "#404040" },
      color: "#404040",
      width: 4,
    },
    "ATL-FLL-DL": {
      id1: "ATL",
      id2: "FLL",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 4,
    },
    "BOS-DCA-US": {
      id1: "BOS",
      id2: "DCA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "US", bold: true, color: "#404040" },
      color: "#404040",
      width: 4,
    },
    "ORD-SFO-UA": {
      id1: "ORD",
      id2: "SFO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 4,
    },
    "ATL-DCA-DL": {
      id1: "ATL",
      id2: "DCA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 4,
    },
    "DCA-LGA-US": {
      id1: "DCA",
      id2: "LGA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "US", bold: true, color: "#404040" },
      color: "#404040",
      width: 4,
    },
    "LAX-SFO-UA": {
      id1: "LAX",
      id2: "SFO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 4,
    },
    "DFW-LGA-AA": {
      id1: "DFW",
      id2: "LGA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 4,
    },
    "ATL-TPA-DL": {
      id1: "ATL",
      id2: "TPA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 4,
    },
    "EWR-SFO-UA": {
      id1: "EWR",
      id2: "SFO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "LAX-OAK-WN": {
      id1: "LAX",
      id2: "OAK",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "IAH-LAX-UA": {
      id1: "IAH",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "IAH-ORD-UA": {
      id1: "IAH",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "JFK-LAX-AA": {
      id1: "JFK",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 3,
    },
    "LGA-MIA-AA": {
      id1: "LGA",
      id2: "MIA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 3,
    },
    "BUR-OAK-WN": {
      id1: "BUR",
      id2: "OAK",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "DAL-SAT-WN": {
      id1: "DAL",
      id2: "SAT",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "LAX-SEA-AS": {
      id1: "LAX",
      id2: "SEA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AS", bold: true, color: "#1f405f" },
      color: "#1f405f",
      width: 3,
    },
    "LAS-SAN-WN": {
      id1: "LAS",
      id2: "SAN",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "DFW-LAS-AA": {
      id1: "DFW",
      id2: "LAS",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 3,
    },
    "BOS-LGA-US": {
      id1: "BOS",
      id2: "LGA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "US", bold: true, color: "#404040" },
      color: "#404040",
      width: 3,
    },
    "ATL-JAX-DL": {
      id1: "ATL",
      id2: "JAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "ATL-RDU-DL": {
      id1: "ATL",
      id2: "RDU",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "LAX-SMF-OO": {
      id1: "LAX",
      id2: "SMF",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "OO", bold: true, color: "#8263a0" },
      color: "#8263a0",
      width: 3,
    },
    "EWR-LAX-UA": {
      id1: "EWR",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "DEN-IAH-UA": {
      id1: "DEN",
      id2: "IAH",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "DFW-MIA-AA": {
      id1: "DFW",
      id2: "MIA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 3,
    },
    "ATL-DFW-DL": {
      id1: "ATL",
      id2: "DFW",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "OAK-SAN-WN": {
      id1: "OAK",
      id2: "SAN",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "ATL-MIA-DL": {
      id1: "ATL",
      id2: "MIA",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "ATL-MSP-DL": {
      id1: "ATL",
      id2: "MSP",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "LAS-LAX-WN": {
      id1: "LAS",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "ATL-BOS-DL": {
      id1: "ATL",
      id2: "BOS",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "LAX-ORD-UA": {
      id1: "LAX",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "EWR-ORD-UA": {
      id1: "EWR",
      id2: "ORD",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "DFW-SFO-AA": {
      id1: "DFW",
      id2: "SFO",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "AA", bold: true, color: "#4481ba" },
      color: "#4481ba",
      width: 3,
    },
    "EWR-IAH-UA": {
      id1: "EWR",
      id2: "IAH",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "UA", bold: true, color: "#808080" },
      color: "#808080",
      width: 3,
    },
    "AUS-DAL-WN": {
      id1: "AUS",
      id2: "DAL",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "LAX-SJC-OO": {
      id1: "LAX",
      id2: "SJC",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "OO", bold: true, color: "#8263a0" },
      color: "#8263a0",
      width: 3,
    },
    "ATL-BWI-DL": {
      id1: "ATL",
      id2: "BWI",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "LAS-PHX-WN": {
      id1: "LAS",
      id2: "PHX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },
      color: "#c85150",
      width: 3,
    },
    "ATL-MSY-DL": {
      id1: "ATL",
      id2: "MSY",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "ATL-PHL-DL": {
      id1: "ATL",
      id2: "PHL",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 3,
    },
    "ATL-CLT-DL": {
      id1: "ATL",
      id2: "CLT",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 2,
    },
    "ATL-LAX-DL": {
      id1: "ATL",
      id2: "LAX",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "DL", bold: true, color: "#ff9651" },
      color: "#ff9651",
      width: 2,
    },
    "PHX-SAN-WN": {
      id1: "PHX",
      id2: "SAN",
      end1: { arrow: true },
      end2: { arrow: true },
      label: { text: "WN", bold: true, color: "#c85150" },

// ...truncated 381 lines
<!doctype html>
<html>
  <body>
    <div id="regraph" style="height: 100vh"></div>
    <script type="module" src="./code.jsx"></script>
  </body>
</html>

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.