This example allows you to drag and drop GeoJSON onto the map. Download
[a
sample GeoJSON file](https://developers.google.com/static/maps/documentation/javascript/examples/json/states.json) to test dragging from the device.

For more information about how to work with the map data layer, see the
[google.maps.Data class](https://developers.google.com/maps/documentation/javascript/reference.md.txt#Data).
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/layer-data-dragndrop/app/dist/" allow="fullscreen; "></iframe>

### TypeScript

```typescript
let map: google.maps.Map;

function initMap(): void {
  // set up the map
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    center: new google.maps.LatLng(0, 0),
    zoom: 4,
  });
}

function loadGeoJsonString(geoString: string) {
  try {
    const geojson = JSON.parse(geoString) as any;

    map.data.addGeoJson(geojson);
  } catch (e) {
    alert("Not a GeoJSON file!");
  }

  zoom(map);
}

/**
 * Update a map's viewport to fit each geometry in a dataset
 */
function zoom(map: google.maps.Map) {
  const bounds = new google.maps.LatLngBounds();

  map.data.forEach((feature) => {
    const geometry = feature.getGeometry();

    if (geometry) {
      processPoints(geometry, bounds.extend, bounds);
    }
  });
  map.fitBounds(bounds);
}

/**
 * Process each point in a Geometry, regardless of how deep the points may lie.
 */
function processPoints(
  geometry: google.maps.LatLng | google.maps.Data.Geometry,
  callback: any,
  thisArg: google.maps.LatLngBounds
) {
  if (geometry instanceof google.maps.LatLng) {
    callback.call(thisArg, geometry);
  } else if (geometry instanceof google.maps.Data.Point) {
    callback.call(thisArg, geometry.get());
  } else {
    // @ts-ignore
    geometry.getArray().forEach((g) => {
      processPoints(g, callback, thisArg);
    });
  }
}

/* DOM (drag/drop) functions */
function initEvents() {
  [...document.getElementsByClassName("file")].forEach((fileElement) => {
    fileElement.addEventListener(
      "dragstart",
      (e: Event) => {
        // @ts-ignore
        e.dataTransfer.setData(
          "text/plain",
          JSON.stringify(files[Number((e.target as HTMLElement).dataset.value)])
        );
        console.log(e);
      },
      false
    );
  });

  // set up the drag & drop events
  const mapContainer = document.getElementById("map") as HTMLElement;

  mapContainer.addEventListener("dragenter", addClassToDropTarget, false);
  mapContainer.addEventListener("dragover", addClassToDropTarget, false);
  mapContainer.addEventListener("drop", handleDrop, false);
  mapContainer.addEventListener("dragleave", removeClassFromDropTarget, false);
}

function addClassToDropTarget(e: Event) {
  e.stopPropagation();
  e.preventDefault();
  document.getElementById("map")!.classList.add("over");
  return false;
}

function removeClassFromDropTarget(e: Event) {
  document.getElementById("map")!.classList.remove("over");
}

function handleDrop(e: DragEvent) {
  e.preventDefault();
  e.stopPropagation();
  removeClassFromDropTarget(e);

  const files = (e.dataTransfer as DataTransfer).files;

  if (files.length) {
    // process file(s) being dropped
    // grab the file data from each file
    for (let i = 0, file; (file = files[i]); i++) {
      const reader = new FileReader();

      reader.onload = function (e) {
        loadGeoJsonString(reader.result as string);
      };

      reader.onerror = function (e) {
        console.error("reading failed");
      };

      reader.readAsText(file);
    }
  } else {
    // process non-file (e.g. text or html) content being dropped
    // grab the plain text version of the data
    const plainText = (e.dataTransfer as DataTransfer).getData("text/plain");

    console.log(plainText);

    if (plainText) {
      loadGeoJsonString(plainText);
    }
  }

  // prevent drag event from bubbling further
  return false;
}

function initialize() {
  initMap();
  initEvents();
}

const files = [
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Polygon",
          coordinates: [
            [
              [-99.49218749999999, -11.867350911459294],
              [24.960937499999996, -11.867350911459294],
              [24.960937499999996, 47.517200697839414],
              [-99.49218749999999, 47.517200697839414],
              [-99.49218749999999, -11.867350911459294],
            ],
          ],
        },
      },
    ],
  },
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [81.2109375, 50.064191736659104],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [103.35937499999999, -47.98992166741417],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-46.05468749999999, 64.01449619484472],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-113.203125, 37.996162679728116],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-73.828125, -32.249974455863295],
        },
      },
    ],
  },
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "LineString",
          coordinates: [
            [147.65625, -5.266007882805485],
            [118.47656249999999, 43.83452678223682],
            [80.85937499999999, -30.145127183376115],
            [35.15625, 51.83577752045248],
            [-15.468749999999998, -23.563987128451217],
            [-29.53125, 44.33956524809713],
            [-73.47656249999999, -32.842673631954305],
            [-104.765625, 35.460669951495305],
          ],
        },
      },
    ],
  },
];

declare global {
  interface Window {
    initialize: () => void;
  }
}
window.initialize = initialize;
```

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

```javascript
let map;

function initMap() {
  // set up the map
  map = new google.maps.Map(document.getElementById("map"), {
    center: new google.maps.LatLng(0, 0),
    zoom: 4,
  });
}

function loadGeoJsonString(geoString) {
  try {
    const geojson = JSON.parse(geoString);

    map.data.addGeoJson(geojson);
  } catch (e) {
    alert("Not a GeoJSON file!");
  }

  zoom(map);
}

/**
 * Update a map's viewport to fit each geometry in a dataset
 */
function zoom(map) {
  const bounds = new google.maps.LatLngBounds();

  map.data.forEach((feature) => {
    const geometry = feature.getGeometry();

    if (geometry) {
      processPoints(geometry, bounds.extend, bounds);
    }
  });
  map.fitBounds(bounds);
}

/**
 * Process each point in a Geometry, regardless of how deep the points may lie.
 */
function processPoints(geometry, callback, thisArg) {
  if (geometry instanceof google.maps.LatLng) {
    callback.call(thisArg, geometry);
  } else if (geometry instanceof google.maps.Data.Point) {
    callback.call(thisArg, geometry.get());
  } else {
    // @ts-ignore
    geometry.getArray().forEach((g) => {
      processPoints(g, callback, thisArg);
    });
  }
}

/* DOM (drag/drop) functions */
function initEvents() {
  [...document.getElementsByClassName("file")].forEach((fileElement) => {
    fileElement.addEventListener(
      "dragstart",
      (e) => {
        // @ts-ignore
        e.dataTransfer.setData(
          "text/plain",
          JSON.stringify(files[Number(e.target.dataset.value)]),
        );
        console.log(e);
      },
      false,
    );
  });

  // set up the drag & drop events
  const mapContainer = document.getElementById("map");

  mapContainer.addEventListener("dragenter", addClassToDropTarget, false);
  mapContainer.addEventListener("dragover", addClassToDropTarget, false);
  mapContainer.addEventListener("drop", handleDrop, false);
  mapContainer.addEventListener("dragleave", removeClassFromDropTarget, false);
}

function addClassToDropTarget(e) {
  e.stopPropagation();
  e.preventDefault();
  document.getElementById("map").classList.add("over");
  return false;
}

function removeClassFromDropTarget(e) {
  document.getElementById("map").classList.remove("over");
}

function handleDrop(e) {
  e.preventDefault();
  e.stopPropagation();
  removeClassFromDropTarget(e);

  const files = e.dataTransfer.files;

  if (files.length) {
    // process file(s) being dropped
    // grab the file data from each file
    for (let i = 0, file; (file = files[i]); i++) {
      const reader = new FileReader();

      reader.onload = function (e) {
        loadGeoJsonString(reader.result);
      };

      reader.onerror = function (e) {
        console.error("reading failed");
      };

      reader.readAsText(file);
    }
  } else {
    // process non-file (e.g. text or html) content being dropped
    // grab the plain text version of the data
    const plainText = e.dataTransfer.getData("text/plain");

    console.log(plainText);
    if (plainText) {
      loadGeoJsonString(plainText);
    }
  }
  // prevent drag event from bubbling further
  return false;
}

function initialize() {
  initMap();
  initEvents();
}

const files = [
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Polygon",
          coordinates: [
            [
              [-99.49218749999999, -11.867350911459294],
              [24.960937499999996, -11.867350911459294],
              [24.960937499999996, 47.517200697839414],
              [-99.49218749999999, 47.517200697839414],
              [-99.49218749999999, -11.867350911459294],
            ],
          ],
        },
      },
    ],
  },
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [81.2109375, 50.064191736659104],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [103.35937499999999, -47.98992166741417],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-46.05468749999999, 64.01449619484472],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-113.203125, 37.996162679728116],
        },
      },
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "Point",
          coordinates: [-73.828125, -32.249974455863295],
        },
      },
    ],
  },
  {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        properties: {},
        geometry: {
          type: "LineString",
          coordinates: [
            [147.65625, -5.266007882805485],
            [118.47656249999999, 43.83452678223682],
            [80.85937499999999, -30.145127183376115],
            [35.15625, 51.83577752045248],
            [-15.468749999999998, -23.563987128451217],
            [-29.53125, 44.33956524809713],
            [-73.47656249999999, -32.842673631954305],
            [-104.765625, 35.460669951495305],
          ],
        },
      },
    ],
  },
];

window.initialize = initialize;
```

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

### CSS

```css
html {
  height: 100%;
}

body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

#map {
  height: 100%;
}
#map.over {
  opacity: 0.5;
  background-color: rgba(100, 100, 100, 0.5);
}

#sidebar {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: auto;
}

.file {
  display: flex;
  flex-flow: column;
  margin-top: 1em;
  cursor: move;
  text-align: center;
}
.file:hover .material-icons {
  color: darkorange;
}
.file:hover .filename {
  font-weight: bold;
}
.file .material-icons {
  font-size: 50px;
  color: orange;
}
.file .material-icons:hover {
  color: darkorange;
}
.file .filename {
  margin-top: 0.5em;
  font-size: 20px;
  color: #333333;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#container {
  height: 100%;
  display: flex;
}

#sidebar {
  flex-basis: 15rem;
  flex-grow: 1;
  padding: 1rem;
  max-width: 30rem;
  height: 100%;
  box-sizing: border-box;
  overflow: auto;
}

#map {
  flex-basis: 0;
  flex-grow: 4;
  height: 100%;
}
```

### HTML

```html
<html>
  <head>
    <title>Data Layer: Drag and Drop GeoJSON</title>

    <link
      href="https://unpkg.com/material-components-web@6.0.0/dist/material-components-web.css"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
    />

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="container">
      <div id="map"></div>
      <div id="sidebar" class="mdc-typography">
        <div class="file" draggable="true" data-value="0">
          <span class="material-icons">text_snippet</span>
          <div class="filename">polygons.geojson</div>
        </div>
        <div class="file" draggable="true" data-value="1">
          <span class="material-icons">text_snippet</span>
          <div class="filename">points.geojson</div>
        </div>
        <div class="file" draggable="true" data-value="2">
          <span class="material-icons">text_snippet</span>
          <div class="filename">polyline.geojson</div>
        </div>
      </div>
    </div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initialize&v=weekly"
      defer
    ></script>
  </body>
</html>
```

### Clone Sample


Git and Node.js are required to run this sample locally. Follow these [instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) to install Node.js and NPM. The following commands clone, install dependencies and start the sample application.

```javascript
  git clone -b sample-layer-data-dragndrop https://github.com/googlemaps/js-samples.git
  cd js-samples
  npm i
  npm start
```


Other samples can be tried by switching to any branch beginning with `sample-SAMPLE_NAME`.

```javascript
  git checkout sample-SAMPLE_NAME
  npm i
  npm start
```