npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-turkey-map

v2.0.3

Published

Customizable Turkey map

Readme

react-turkey-map

Customizable Turkey map

npm license

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

JSFiddle (UMD)

Preview

Basic Map

Colorful Map

Zoom, Pan & Markers

Installation

Install with NPM

npm install react-turkey-map

Usage

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 too

Without 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 maths

Contribution

Feel free to contribute. Open a new issue, or make a pull request.

License

MIT