react-turkey-map
v2.0.3
Published
Customizable Turkey map
Maintainers
Readme
react-turkey-map
Customizable Turkey map
Demo
Basic Map
PlayCode - StackBlitz - CodeSandbox - Vercel (Next.js) - CodePen (UMD) - JSFiddle (UMD)
Colorful Map
PlayCode - StackBlitz - CodeSandbox - Vercel (Next.js) - CodePen (UMD) - JSFiddle (UMD)
Zoom, Pan & Markers
Preview
Basic Map
Colorful Map
Zoom, Pan & Markers
Installation
Install with NPM
npm install react-turkey-mapUsage
import TurkeyMap from 'react-turkey-map'
export default () => {
return (
<TurkeyMap />
)
}Props
<TurkeyMap
zoomable
showTooltip
minZoom={1}
maxZoom={40}
markers={[]}
colorData={{}}
clickableCities
showCityTooltip
tooltipData={{}}
showMarkerTooltip
onCityClick={({ plate, city }, event) => {}}
onMarkerClick={({ id, plate, city }, event) => {}}
/>
// types and defaults
markers: array (default: [])
minZoom: number (default: 1)
maxZoom: number (default: 40)
colorData: object (default: {})
zoomable: bool (default: false)
tooltipData: object (default: {})
showTooltip: bool (default: true)
clickableCities: bool (default: true)
onCityClick: function (default: undefined)
showCityTooltip: bool (default: showTooltip)
onMarkerClick: function (default: undefined)
renderMarkerPopup: function (default: undefined)
showMarkerTooltip: bool (default: showTooltip, false with renderMarkerPopup)
// colorData prop
// plate: city color
colorData={{
'34': '#071E58',
'06': '#253494',
'35': '#253494',
'16': '#253494',
'07': '#225EA8'
}}
// tooltipData prop
// plate: city tooltip
tooltipData={{
'34': '15.655.924',
'06': '5.803.482',
'35': '4.479.525',
'16': '3.214.571',
'07': '2.696.249'
}}
// markers prop
// placed by real coordinates, on the same projection as the provinces
markers={[
{ id: 'istanbul', title: 'İstanbul', latitude: 41.0082, longitude: 28.9784 },
{ id: 'ankara', title: 'Ankara', latitude: 39.9334, longitude: 32.8597, color: '#1b6ac9' }
]}
// id and title are optional, color defaults to #e2231a
// markers with missing or unparseable coordinates are skipped
// onCityClick and onMarkerClick both hand back the province involved,
// plus the original click event
// onCityClick prop
onCityClick={({ plate, city }, event) => {
console.log(plate, city)
// 06 Ankara
}}
// onMarkerClick prop
onMarkerClick={({ id, plate, city }, event) => {
console.log(id, plate, city)
// istanbul 34 İstanbul
}}
// plate and city are the province involved, resolved for a marker from its
// coordinates, and are both null for a marker outside every province
// your other marker fields (title, latitude, longitude, color) come along tooWithout a callback, both log to the console instead, so clicks are visible out of the box.
Marker tooltips
Markers get the built-in tooltip on hover, showing their title. It follows
the cursor, so it always describes whatever the pointer is over and can never
go stale.
On touch there is no cursor to follow, so a tap opens the tooltip above the point you tapped and pins it to the map: it travels with its province or marker as you pan and zoom, and disappears with them at the edge. Tapping another province moves it there, and tapping off the map closes it.
showTooltip turns both kinds off. To keep one and drop the other, set
showCityTooltip or showMarkerTooltip:
// markers respond, provinces stay quiet
<TurkeyMap markers={markers} showCityTooltip={false} />For a tooltip on click instead, onMarkerClick hands you the click event, so
you can place your own anywhere on the page:
import { useState } from 'react'
import TurkeyMap from 'react-turkey-map'
export default () => {
const [popup, setPopup] = useState(null)
const onMarkerClick = (marker, event) => {
setPopup({
text: `${marker.title} — ${marker.city} (${marker.plate})`,
top: event.pageY + 12,
left: event.pageX + 12
})
}
return (
<div>
{popup
? (
<div style={{ position: 'absolute', top: popup.top, left: popup.left }}>
{popup.text}
</div>
)
: null}
<TurkeyMap
zoomable
markers={markers}
onMarkerClick={onMarkerClick}
/>
</div>
)
}A tooltip placed this way stays where it was clicked, so zooming or panning afterwards leaves it behind while the marker moves on. For one that follows the marker, hand the map the content instead and let it do the positioning:
<TurkeyMap
zoomable
markers={markers}
renderMarkerPopup={marker => (
<div className='popup'>
{marker.title} — {marker.city} ({marker.plate})
</div>
)}
/>Clicking a marker opens the popup above it and it stays there through zoom,
pan and double click, disappearing once the marker itself is off the map.
Clicking anywhere else closes it. The marker you get is the same one
onMarkerClick receives, province and all.
With renderMarkerPopup set, the hover tooltip on markers turns itself off, so
you don't get both. Pass showMarkerTooltip explicitly if you want them
together.
Map without clickable provinces
For a map where only the markers respond, turn the provinces off entirely:
<TurkeyMap
zoomable
markers={markers}
showCityTooltip={false}
clickableCities={false}
/>clickableCities={false} stops onCityClick firing, and drops the pointer
cursor and hover highlight with it, so the provinces read as a backdrop.
Zoom and pan
zoomable is off by default. Turning it on adds:
- mouse wheel zoom around the cursor
- double click to zoom 2x around the cursor
- drag to pan
- pinch with two fingers to zoom around the point between them
- one finger drag to pan, and double tap to zoom 2x
- tooltips pinned to the map, since a tap leaves no cursor to follow
Touch gestures work the way they do in a map app: the pinch keeps whatever is
between your fingers under them while it zooms, and lifting one finger hands
the pan over to the one still down. While zoomable is on the map sets
touch-action: none, so a drag that starts on it pans the map rather than
scrolling the page.
Province strokes and marker sizes stay constant on screen at any zoom, and the
map is clamped so panning can never expose empty space, so zooming back out to
minZoom always brings it back to where it started.
Map data
The 81 provinces come from Natural Earth
10m admin-1 states/provinces (public domain), drawn in Web Mercator and fitted
to a 1007x443 viewBox. Markers use that same projection, so pins and province
shapes always agree.
src/geoCities.js is generated. To rebuild it:
npm run build:geo # downloads the ~40MB source on first run
npm run verify # checks the projection, the outlines and the zoom mathsContribution
Feel free to contribute. Open a new issue, or make a pull request.
