fc373745
1/28/2019 - 11:01 PM

trying to convert map-transition.js to map-transition.tsx

trying to convert map-transition.js to map-transition.tsx

// zooming to Los Angeles, Dallas, Chicago, New York
// https://bl.ocks.org/mbostock/b783fbb2e673561d214e09c7fb5cedee
// https://bl.ocks.org/mbostock/4090848

const CITIES = ['Los Angeles', 'New York', 'Dallas', 'Chicago'];
const width = 960;
const height = 600;

let cities;
let city;
let index = 0;

const svg = d3.select('svg').append('g');
const projection = d3.geoMercator();

const path = d3.geoPath()
    .projection(projection);

const zoomed = () => {
    svg.attr('transform', `translate(${d3.event.transform.x}, ${d3.event.transform.y}) scale(${d3.event.transform.k}, ${d3.event.transform.k})`);
};

const transform = () => {
    // create a geojson point
    const cityPoint = {
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": city.lnglat
        },
        "properties": {
            "name": "Dinagat Islands"
        }
    };

    // get the center in pixels
    const centroid = path.centroid(cityPoint);
    const x = width / 2 - centroid[0];
    const y = height / 2 - centroid[1];

    // return the transform translate
    return d3.zoomIdentity
        .translate(x, y);
}

const transition = () => {
    index++;
    index = index % CITIES.length;

    city = cities[index];

    svg.transition()
        .delay(500)
        .duration(3000)
        .call(zoom.transform, transform)
        .on('end', () => { svg.call(transition); });
}

const zoom = d3.zoom()
    .on('zoom', zoomed);

const drawChart = (data) => {
    cities = data[0].filter( d => {
        return CITIES.indexOf(d.PlaceName) !== -1;
    })
    .map( d => {
        const lnglat = d.Geolocation.replace(/[\(\)\s]/g, '').split(',').map( d => +d).reverse();
        return {
            stateAbbr: d.StateAbbr,
            placeName: d.PlaceName,
            lng: lnglat[0],
            lat: lnglat[1],
            lnglat: lnglat
        };
    });

    city = cities[index];

    const us = data[1];

    const center = cities[3].lnglat;

    // svg.call(zoom.transform, transform);
    svg.call(transition);

    projection
        .scale(7000)
        .center(center)

    svg.append('g')
        .attr('class', 'states')
        .selectAll('path')
        .data(topojson.feature(us, us.objects.states).features)
        .enter().append('path')
        .attr('d', path);

    svg.append('path')
        .attr('class', 'state-borders')
        .attr('d', path(topojson.mesh(us, us.objects.states, (a, b) => a !== b )));

    const point = svg.selectAll('.city')
        .data(cities).enter()
        .append('g')
        .classed('city', true)
        .attr('transform', d => `translate(${projection(d.lnglat)[0]},${projection(d.lnglat)[1]})`);

    // add circles to svg
    point.append('circle')
        .classed('city-circle', true)
        .attr('r', '8px');

    // add circles to svg
    point.append('text')
        .classed('city-text', true)
        .text(d => d.placeName);
};

const citiesRequest = d3.csv('us_cities.csv');
const mapRequest = d3.json('us.json');

Promise.all([citiesRequest, mapRequest])
.then( result => {
    drawChart(result);
})
.catch(error => {
    throw (error);
});
import { geoMercator, geoPath } from "d3-geo";
import { event, select } from "d3-selection";
import "d3-transition";
import { zoom, zoomIdentity } from "d3-zoom";
import React, { useEffect, useRef, useState } from "react";
import styled, { createGlobalStyle } from "styled-components";
import { feature, mesh } from "topojson";
import us from "./us.json";

type City = {
    name: string;
    lnglat: number[];
};

const MapStyles = styled.svg`
    background-color: #373745;
`;

const Global = createGlobalStyle`
    .counties{
        stroke: #000;
        fill: #373745;
        &:hover{
            fill: black
        }
    }
    
    .county-borders{
        fill: none;
        stroke: white;
        stroke-width: 1px;
        stroke-linejoin: round;
        stroke-linecap: round;
        pointer-events: none;
    }
    `;

const Map: React.FunctionComponent = () => {
    const cities = [
        { name: "Seattle", lnglat: [47.6062, -122.3321] },
        { name: "Los Angeles", lnglat: [34.0522, -118.2437] },
        { name: "Dallas", lnglat: [32.7767, -96.797] },
        { name: "Chicago", lnglat: [41.8781, -87.6298] },
        { name: "New York City", lnglat: [40.7128, -74.006] }
    ];
    const mapRef = useRef(null);
    const containerRef = useRef(null);
    const projection = geoMercator();
    const path = geoPath().projection(projection);
    const [city, setCity] = useState<City | null>(cities[3]);
    const [index, setIndex] = useState(3);

    const zoomed = () => {
        select(mapRef.current).attr(
            "transform",
            //prettier-ignore
            `translate(${event.transform.x}, ${event.transform.y}) scale(${event.transform.k},${event.transform.k})`
        );
    };

    const transform = () => {
        const cityPoint = {
            type: "Feature",
            geometry: {
                type: "Point",
                //@ts-ignore
                coordinates: city.lnglat
            },
            properties: {
                name: "x"
            }
        };

        const centroid = path.centroid(cityPoint as any);
        const x = 960 / 2 - centroid[0];
        const y = 600 / 2 - centroid[1];

        return zoomIdentity.translate(x, y);
    };

    const zoom2 = zoom().on("zoom", zoomed);

    const transition = () => {
        if (index + 1 > cities.length) {
            setIndex((index + 1) % cities.length);
        } else {
            setIndex(index + 1);
        }
        setCity(cities[index]);
        select(mapRef.current)
            .transition()
            .delay(500)
            .duration(3000)
            .call(zoom2.transform as any, transform)
            .on("end", () => {
                select(mapRef.current).call(transition);
            });
    };

    useEffect(() => {
        drawMap();
    }, []);

    const drawMap = () => {
        const mapSelection = select(mapRef.current);
        const containerSelection = select(containerRef.current);
        const newCities = cities.map(d => {
            lnglat: d.lnglat.reverse();
        });

        const center = cities[3].lnglat.reverse();
        console.log(center);

        mapSelection.call(transition);

        console.log(projection);
        projection.scale(7000).center(center as any);

        mapSelection
            .selectAll("path")
            //@ts-ignore
            .data(feature(us, us.objects.counties).features)
            .enter()
            .append("path")
            .attr("class", "counties")
            .attr("d", path as any);

        mapSelection
            .append("path")

            .attr("d", path(
                //@ts-ignore
                mesh(us, us.objects.counties, function(a, b) {
                    return a !== b;
                })
            ) as any)
            .attr("class", "county-borders");
    };

    return (
        <div>
            <Global />
            <MapStyles ref={containerRef} width={960} height={600}>
                <g ref={mapRef} />
            </MapStyles>
        </div>
    );
};
export default Map;