@sechak.agency/moromap
v0.1.0
Published
Zero-dependency-fetch interactive Morocco map for JS/TS — regions & provinces/prefectures, labels, data markers, choropleths, themes, search, export (SVG/PNG). Ships with bundled geo-data and an optional React wrapper.
Maintainers
Readme
MoroMap
Interactive, dependency-light Morocco map for the browser — regions and provinces/prefectures, labels, data markers, choropleths, legends, search and SVG/PNG export. Works as vanilla TypeScript or as an optional React component. The geographic data (boundaries + city coordinates) is bundled in the package, so there is nothing to fetch at runtime.
npm install @sechak.agency/moromap- Vanilla TS/JS — a single
MoroccoMapclass, no framework required. - React — a thin
<MoroccoMapView />wrapper (@sechak.agency/moromap/react), React is an optional peer dependency. - Two levels — 12 regions or 75 provinces/prefectures.
- Choropleths — colour zones by data, with automatic legends.
- Data markers — points sized/coloured by value, with clustering.
- 9 built-in themes + build-your-own from a single accent colour.
- Trilingual names — French, Arabic, Amazigh (Tifinagh) where available.
- Export — SVG, PNG (Retina), and print.
- Search — built-in autocomplete over the current level's zones.
- CSS is auto-injected; no separate stylesheet import required.
Quick start (vanilla)
import { MoroccoMap } from '@sechak.agency/moromap';
const map = new MoroccoMap(document.getElementById('map')!, {
level: 'regions',
labelMode: 'auto',
onFeatureClick: (name) => console.log('clicked', name),
});The container should have a width and a height — the map fills it responsively.
Quick start (React)
import { MoroccoMapView } from '@sechak.agency/moromap/react';
export function Map() {
return (
<div style={{ width: 480, height: 560 }}>
<MoroccoMapView level="regions" labelMode="auto" searchable />
</div>
);
}React is an optional peer dependency — install it only if you use
@sechak.agency/moromap/react.
Choropleth (colour by data)
import { MoroccoMap, colorScaleFromData } from '@sechak.agency/moromap';
const values = {
'Casablanca-Settat': 1200,
'Rabat-Salé-Kénitra': 800,
// ...
};
const scale = colorScaleFromData(Object.values(values));
new MoroccoMap(el, {
level: 'regions',
colorScale: (name) => scale.scale(values[name]),
legend: { scale, title: 'Établissements' },
});Data markers
import { MoroccoMap, CITIES, cityMarkers } from '@sechak.agency/moromap';
new MoroccoMap(el, {
markers: cityMarkers(CITIES), // 91 Moroccan cities, ready to use
markerSizeRange: [4, 20], // size by marker.value
clusterMarkers: true, // merge nearby points
});Themes
import { MoroccoMap, DARK_THEME, themeFromAccent, THEME_PRESETS } from '@sechak.agency/moromap';
// A preset:
new MoroccoMap(el, { theme: DARK_THEME });
// Or derive a full, coherent theme from one brand colour:
new MoroccoMap(el, { theme: themeFromAccent('#6d28d9', 'dark') });Presets: light, dark, ocean, sahara, royal, monochrome, sunset,
emerald, slate (all available via THEME_PRESETS).
Export
map.exportSvg({ filename: 'maroc' });
await map.exportPng({ scale: 3, background: '#fff' });
map.print();In React, drive the same actions through a ref:
const ref = useRef<MoroccoMapHandle>(null);
// ref.current?.exportPng({ scale: 2 })API overview
new MoroccoMap(container, options)
Key options (see full JSDoc types in your editor via MoroccoMapOptions):
| Option | Type | Description |
| --- | --- | --- |
| level | 'regions' \| 'provinces' | Detail level (default 'regions'). |
| labelMode | 'none' \| 'always' \| 'hover' \| 'auto' | Zone name display. |
| labelPlacement | 'inline' \| 'callout' \| 'sidebar' \| 'tooltip-only' | Where values/labels render. |
| renderStyle | 'solid' \| 'outline' \| 'dotted' | Fill style. |
| theme | Partial<MoroccoMapTheme> | Merged with the default theme. |
| colorScale | (name) => string | Choropleth colour per zone. |
| zoneColors / zoneValues | Record<string, …> | Hand-set colours / values per zone. |
| markers | MapMarker[] | Data points to overlay. |
| markerSizeRange | [number, number] | Size markers by value. |
| clusterMarkers | boolean | Merge nearby markers into clusters. |
| legend | { scale, title?, position? } | Auto-rendered choropleth legend. |
| zoomable | boolean | Mouse/trackpad zoom & pan. |
| isolateOnClick | boolean | Zoom into a zone and dim the rest. |
| attribution | boolean | Show the required "© OpenStreetMap contributors" credit (default true). |
| attributionPosition | 'bottom-left' \| 'bottom-right' \| 'top-left' \| 'top-right' | Where the credit renders (default 'bottom-right'). |
| onFeatureClick / onFeatureHover / onMarkerClick | callbacks | Interaction hooks. |
Named exports
- Map:
MoroccoMap - React:
MoroccoMapView,MoroccoMapViewProps,MoroccoMapHandle(from@sechak.agency/moromap/react) - Themes:
LIGHT_THEME,DARK_THEME,OCEAN_THEME,SAHARA_THEME,ROYAL_THEME,MONOCHROME_THEME,SUNSET_THEME,EMERALD_THEME,SLATE_THEME,THEME_PRESETS,resolveTheme,prefersDarkMode,themeFromAccent - Colour scales:
sequentialScale,divergingScale,colorScaleFromData - Cities:
CITIES,citiesOfRegion,citiesOfProvince,cityMarkers - Search:
SearchIndex - Clustering:
clusterMarkers - Export:
exportPng,exportSvg,printMap - Plus TypeScript types for every option and data shape.
Styling
CSS is injected automatically the first time a map is created — you do not need to import a stylesheet. If your bundler or CSP requires an explicit stylesheet instead, one is shipped:
import '@sechak.agency/moromap/style.css';Requirements
- Node >= 18 (for building/tooling; the library itself runs in the browser).
- A DOM environment — this is a browser library (SVG + Canvas for PNG export).
- React >= 18 only if you use
@sechak.agency/moromap/react.
Data & licence
The map boundaries and city coordinates are derived from OpenStreetMap and are licensed under the Open Database License (ODbL) v1.0, which requires crediting © OpenStreetMap contributors wherever the map is shown publicly.
This credit is displayed automatically in a corner of the map (see
attribution / attributionPosition above) — you don't need to add it
yourself. Only disable it (attribution: false) if you already display the
same credit elsewhere on the page (e.g. in your site's footer); in that case,
keeping the licence obligation satisfied is your responsibility.
The source code is released under the MIT License. See LICENSE for the full terms of both.
