# Malaysia map — data exports

Ready-to-use Malaysia geometry in standard formats. All 16 admin-1 regions
(13 states + Kuala Lumpur, Putrajaya, **Labuan**) and 159 admin-2 *daerah*.

Regenerate after changing the source data: `python3 data/bake.py && python3 data/export.py`

| File | What it is | Coordinate space |
|------|-----------|------------------|
| `malaysia-states.svg` | 16 states, themed, self-contained | SVG viewBox `0 0 1338 590` |
| `malaysia-states-districts.svg` | states + 159 districts (`<g id="districts">`) | same |
| `malaysia-blank.svg` | unstyled outline — a tracing template | same |
| `malaysia.geojson` | states, **original lng/lat**, normalized props | WGS84 lng/lat |
| `malaysia-districts.geojson` | districts, original lng/lat, + parent `state` | WGS84 lng/lat |
| `malaysia-paths.json` | the baked projected paths + projection params | SVG viewBox |

Every `<path>` carries stable hooks: `id="state-johor"`, `data-slug`, `data-name`,
`data-type` (states) / `data-state`, `data-slug`, `data-name` (districts).

## SVG — drop straight into HTML / Figma / Illustrator

```html
<img src="malaysia-states.svg" alt="Map of Malaysia" width="600">
<!-- or inline it and style/script the paths by id -->
<object data="malaysia-states-districts.svg" type="image/svg+xml"></object>
```

The SVG is flat by design. Re-colour it by editing the `<style>` block at the top
(`.state`, `.district`, `.sea`), or per-path via the `id` / `data-*` hooks.

## GeoJSON — d3 / Leaflet / Mapbox / Turf

```js
const states = await fetch('malaysia.geojson').then(r => r.json());
// properties: { slug, name, type:'state'|'ft' }
// districts properties: { slug, name, state }  ← state = parent slug
```

Want TopoJSON (tiny, for d3)? The GeoJSON above is the input — one command:

```bash
npx -p topojson-server geo2topo states=malaysia.geojson > malaysia.topojson
```

## Projected paths JSON — any language, no JS engine

`malaysia-paths.json` = `{ projection, viewBox, states[], districts[] }` where each
entry has the **already-projected** SVG `d` string. Use it to render the exact same
compact layout (Borneo slid west) anywhere.

### Place a pin at a real lng/lat

The paths are baked with a Mercator projection that slides East Malaysia west, so to
drop a marker at real coordinates you must project through the same maths. The params
live in `paths.projection`.

**JavaScript**
```js
const P = paths.projection;
function project(lng, lat) {
  const D = Math.PI / 180;
  const mx = lng * D;
  const my = Math.log(Math.tan(Math.PI / 4 + (lat * D) / 2));
  let x = (mx - P.minx) * P.scale + P.pad;
  const y = (P.maxy - my) * P.scale + P.pad;
  if (lng >= P.eastLng) x -= P.shift;   // slide Borneo west
  return { x: x + P.offX, y: y + P.offY };
}
project(101.7117, 3.1578); // KLCC → {x, y} in viewBox space
```

**Python**
```python
import math
def project(lng, lat, P):            # P = paths["projection"]
    D = math.pi / 180
    mx = lng * D
    my = math.log(math.tan(math.pi / 4 + (lat * D) / 2))
    x = (mx - P["minx"]) * P["scale"] + P["pad"]
    y = (P["maxy"] - my) * P["scale"] + P["pad"]
    if lng >= P["eastLng"]:
        x -= P["shift"]
    return (x + P["offX"], y + P["offY"])
```

## License / provenance

States: codeforamerica/click_that_hood. Districts (ADM2) + Labuan: geoBoundaries
gbOpen (MYS). Check each source's license before commercial redistribution.
