BaseMap.jsx 4.15 KB
Newer Older
Florent Chehab's avatar
Florent Chehab committed
1
import React, { useCallback, useState } from "react";
2
3
import PropTypes from "prop-types";

4
import ReactMapboxGl, { Feature, Layer, Popup } from "react-mapbox-gl";
Florent Chehab's avatar
Florent Chehab committed
5
import { makeStyles, useTheme } from "@material-ui/styles";
6
import UnivMapPopup from "./UnivMapPopup";
7
import Legend, { getLegendColorOpacity } from "./Legend";
8
9
10
11

const Map = ReactMapboxGl({
  dragRotate: false,
  pitchWithRotate: false,
12
  maxZoom: 12
13
14
});

Florent Chehab's avatar
Florent Chehab committed
15
16
17
18
19
20
21
22
23
24
const useStyles = makeStyles(theme => ({
  mapContainer: {
    width: "100%",
    [theme.breakpoints.up("lg")]: {
      height: "45vh",
      minHeight: 600
    },
    [theme.breakpoints.down("md")]: {
      height: "60vh"
    }
Estelle Veisemburger's avatar
Estelle Veisemburger committed
25
26
27
28
29
  },
  legend: {
    position: "absolute",
    top: 0,
    left: 0,
30
31
    zIndex: 1,
    padding: theme.spacing(1)
Florent Chehab's avatar
Florent Chehab committed
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  }
}));

/**
 * @constant
 * @type {{center: number[], zoom: [number]}}
 */
const DEFAULT_STATUS = {
  center: [53.94, 41.13],
  zoom: [0.86]
};

// variable to hold the map center in a generic way without globalState
const ALL_MAPS = {};

47
48
49
50
51
/**
 * Custom react-wrapper on top of MapBoxGlJs to handle our maps in a generic manner.
 *
 * If an id is provided, the state of the map will be automatically saved and regenerated.
 */
Gautier D's avatar
Gautier D committed
52
53
function BaseMap({ id, universities }) {
  console.log("iciciciiojoij", universities);
Florent Chehab's avatar
Florent Chehab committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  const theme = useTheme();
  const classes = useStyles();

  const [popup, setPopup] = useState(undefined);

  const saveStatus = useCallback(
    map => {
      if (typeof id !== "undefined") {
        const center = map.getCenter();
        ALL_MAPS[id] = {
          center: [center.lng, center.lat],
          zoom: [map.getZoom()]
        };
      }
    },
    [id, ALL_MAPS]
  );
71

Gautier D's avatar
Gautier D committed
72
  const openPopup = useCallback(universityInfo => setPopup(universityInfo), []);
Florent Chehab's avatar
Florent Chehab committed
73
  const closePopup = useCallback(() => setPopup(undefined), []);
74

Florent Chehab's avatar
Florent Chehab committed
75
  const toggleHover = useCallback((mapInstance, cursor) => {
76
77
    // eslint-disable-next-line no-param-reassign
    mapInstance.getCanvas().style.cursor = cursor;
Florent Chehab's avatar
Florent Chehab committed
78
79
80
81
82
83
84
  }, []);

  const renderLayer = useCallback(
    selected => {
      return (
        <Layer
          type="circle"
Gautier D's avatar
Gautier D committed
85
          id={`universities${selected ? "selected" : "notSelected"}`}
Florent Chehab's avatar
Florent Chehab committed
86
          paint={{
87
88
            "circle-color": getLegendColorOpacity(theme, selected).color,
            "circle-opacity": getLegendColorOpacity(theme, selected).opacity,
Florent Chehab's avatar
Florent Chehab committed
89
90
91
            "circle-radius": 8
          }}
        >
Gautier D's avatar
Gautier D committed
92
          {universities
Florent Chehab's avatar
Florent Chehab committed
93
            .filter(c => c.selected === selected)
Gautier D's avatar
Gautier D committed
94
            .map((universityInfo, idx) => (
Florent Chehab's avatar
Florent Chehab committed
95
96
97
              <Feature
                // eslint-disable-next-line react/no-array-index-key
                key={idx}
Gautier D's avatar
Gautier D committed
98
99
100
101
102
                coordinates={[
                  universityInfo.main_campus_lon,
                  universityInfo.main_campus_lat
                ]}
                onClick={() => openPopup(universityInfo)}
Florent Chehab's avatar
Florent Chehab committed
103
104
105
106
107
108
109
                onMouseEnter={({ map }) => toggleHover(map, "pointer")}
                onMouseLeave={({ map }) => toggleHover(map, "")}
              />
            ))}
        </Layer>
      );
    },
Gautier D's avatar
Gautier D committed
110
    [universities, theme]
Florent Chehab's avatar
Florent Chehab committed
111
  );
Florent Chehab's avatar
Florent Chehab committed
112

Florent Chehab's avatar
Florent Chehab committed
113
  const style = theme.palette.type === "light" ? "light" : "dark";
114

Florent Chehab's avatar
Florent Chehab committed
115
  const mapStatus = { ...DEFAULT_STATUS };
116

Florent Chehab's avatar
Florent Chehab committed
117
118
119
120
  if (typeof id !== "undefined") {
    const previousData = ALL_MAPS[id];
    if (typeof previousData !== "undefined") {
      Object.assign(mapStatus, previousData);
121
122
    }
  }
Florent Chehab's avatar
Florent Chehab committed
123
124

  return (
Gautier D's avatar
Gautier D committed
125

Estelle Veisemburger's avatar
Estelle Veisemburger committed
126
127
128
129
130
131
132
133
    <div style={{ position: "relative" }}>
      <Map
        style={`/map-server/styles/${style}/style.json`}
        className={classes.mapContainer}
        zoom={mapStatus.zoom}
        center={mapStatus.center}
        onMoveEnd={saveStatus}
      >
Gautier D's avatar
Gautier D committed
134
        {universities && (
Estelle Veisemburger's avatar
Estelle Veisemburger committed
135
136
137
138
139
140
          <>
            {renderLayer(true)}
            {renderLayer(false)}
          </>
        )}
        {popup && (
Gautier D's avatar
Gautier D committed
141
          <Popup key={popup.univId} coordinates={[popup.main_campus_lon, popup.main_campus_lat]}>
Estelle Veisemburger's avatar
Estelle Veisemburger committed
142
143
144
145
146
147
148
149
            <UnivMapPopup {...popup} handleClose={closePopup} />
          </Popup>
        )}
      </Map>
      <div className={classes.legend}>
        <Legend />
      </div>
    </div>
Florent Chehab's avatar
Florent Chehab committed
150
  );
151
152
153
154
}

BaseMap.propTypes = {
  id: PropTypes.string,
Gautier D's avatar
Gautier D committed
155
  universities: PropTypes.array
156
157
};

158
159
BaseMap.defaultProps = {
  id: undefined,
Gautier D's avatar
Gautier D committed
160
  universities: undefined
161
162
};

Florent Chehab's avatar
Florent Chehab committed
163
export default BaseMap;