Skip to content

Map Widget

David Jin edited this page Jun 30, 2023 · 2 revisions

Mapping Contributor Data

Visualization type Description
Chrolopleth Map This visualization uses the contributor metadata from Extracted Features along with the Wikidata API to map where contributors (authors, translators, editors, etc.)  of texts in a workset were born.

Components

Map component

/src/components/widgets/ChorloplethMap/index.tsx

CustomSlider component to change the date range

/src/components/CustomSlider.tsx

How it works

Once get the data from Wiki and import it from the Redux store, using React Hook and useEffect we get the cities array which have city name, coordinate to display markers on the Map.

It uses countries-50m.json under public folder to render a Choropleth map.

Map container, using ref we handle this DOM and append SVG to this.

<div id="graph-container" ref={inputRef} />
const container = d3.select(inputRef.current);

Get cities to show markers on the Map.

const cities = useMemo(() => {
  const cityMap = mapDataHistogram.reduce((map, item) => {
    if (item.city.trim() === '' || item.cityCoords.trim() === '') {
      return map;
    }
    const coords = item.cityCoords.replace('Point(', '').replace(')', '').split(' ');
    const city = map.get(item.city) || { name: item.city, coordinates: [parseFloat(coords[0]), parseFloat(coords[1])], population: 0 };
    city.population++;
    return map.set(item.city, city);
  }, new Map());
  const cities = Array.from(cityMap.values());
  return cities;
}, [mapDataHistogram]);

Draw markers on the map SVG and handle zoom.

// Append markers
const markersG = svg
  .append('g')
  // .attr('transform', 'translate(0, 0) scale(0.5)')
  .selectAll('.marker')
  .data(cities)
  .enter()
  .append('circle')
  .attr('class', 'marker')
  .attr('cx', (d) => projection(d.coordinates)[0])
  .attr('cy', (d) => projection(d.coordinates)[1])
  .attr('r', (d) => (8 / maxPopulation) * d.population)
  // .attr('r', (d) => (maxPopulation > 8 ? (8 / maxPopulation) * d.population : d.population * 1.5))
  .each(function (d) {
    d.initialRadius = d3.select(this).attr('r');
  })
  .attr('fill', '#E91E63')
  .attr('stroke', '#FFFFFF')
  .on('mouseover', (event, d) => handleMarkerClick(event, d))
  .on('mouseout', () => {
    const div = d3.select('#tooltip');
    div.style('opacity', 0);
  });

svg.call(zoom);

function zoomed(event) {
  const { transform } = event;
  g.attr('transform', transform);
  g.attr('stroke-width', 1 / transform.k);

  markersG.attr('transform', transform);
  markersG.attr('stroke-width', 1 / transform.k);
  markersG.attr('r', (d) => d.initialRadius / transform.k);
}

Full source code

Here

Clone this wiki locally