FacilitiesMap.tsx 7.85 KB
Newer Older
1
import * as React from 'react';
2
import ReactMapboxGl, {Marker, Popup} from 'react-mapbox-gl';
3
4
5
6
7
import {getMaxBounds, getCenterOfCampusRegion} from '../utils/mapboxUtils';
import mapboxgl from 'mapbox-gl';
import {removeBrackets} from '../utils/nameUtils';
import { IFacility, CampusRegion, IFacilityLocation } from '../models/facility.model';

8
import MenuItem from '@material-ui/core/Menu';
9
import Select from '@material-ui/core/Select';
10
11
import FormControl from '@material-ui/core/FormControl';
import Typography from '@material-ui/core/Typography';
12

13
const mapboxToken = 'pk.eyJ1IjoibWR1ZmZ5OCIsImEiOiJjaXk2a2lxODQwMDdyMnZzYTdyb3M4ZTloIn0.mSocl7zUnZBO6-CV9cvmnA';
14

15
const Mark = {
16
17
18
19
    backgroundColor: '#e74c3c',
    borderRadius: '50%',
    width: '12px',
    height: '12px',
20
    border: '3px solid #EAA29B'
21
22
};

23
24
25
26
class FacilitiesMap extends React.Component<FacilitiesMapProps, FacilitiesMapState> {
    private Map: any;

    constructor(props: FacilitiesMapProps) {
27
        super(props);
28
29
30

        const {facility, interactive = true} = props;
        const campusRegion = facility && facility.facility_location ? facility.facility_location.campus_region : CampusRegion.Fairfax;
31

32
33
        this.Map = ReactMapboxGl({
            accessToken: mapboxToken,
Mattias J Duffy's avatar
Mattias J Duffy committed
34
            interactive: interactive,
35
36
            attributionControl: false
        });
37

38
        this.state = {
39
40
            maxBounds: getMaxBounds(campusRegion),
            campusRegion: campusRegion,
41
            zoom: [17],
42
            center: facility ? facility.facility_location.coordinate_location.coordinates : getCenterOfCampusRegion(campusRegion),
43
            facilityLocations: [],
44
45
            selectedLocation: null,
            isLoaded: false
46
        };
47
    }
48

49
    componentWillReceiveProps(nextProps: FacilitiesMapProps) {
50
        const {facility, facilities} = nextProps;
51
        const campusRegion = facility && facility.facility_location ? facility.facility_location.campus_region : CampusRegion.Fairfax;
52

53
        this.changeRegion(campusRegion, facility);
54
55
56
57

        if (this.state.facilityLocations.length === 0) {
            this.generateLocationArray(facilities);
        }
58
59
    }

60
    changeRegion = (campusRegion: CampusRegion, facility: IFacility = this.props.facility) => {
61
62
        const facilityLocationExists = facility && facility.facility_location && facility.facility_location.campus_region === campusRegion;

Mattias J Duffy's avatar
Mattias J Duffy committed
63
        const newState = {
64
            maxBounds: getMaxBounds(campusRegion),
65
66
            campusRegion: campusRegion,
            center: facilityLocationExists ? facility.facility_location.coordinate_location.coordinates : getCenterOfCampusRegion(campusRegion),
67
            zoom: [17]
Mattias J Duffy's avatar
Mattias J Duffy committed
68
69
70
71
        };
        setTimeout(() => {
            this.setState(newState);
        }, 100);
72
73
    };

74
75
    generateLocationArray = (facilities: IFacility[]) => {
        const locations: FacilityMapLocation[] = [];
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

        facilities.forEach((facility) => {
            const location = locations.find((loc) => loc.location.id === facility.facility_location.id);
            if (location) {
                location.facilities.push(facility);
            } else {
                locations.push({
                    location: facility.facility_location,
                    facilities: [facility]
                });
            }
        });

        this.setState({
            facilityLocations: locations
        });
    }

94
    selectLocation = (location: FacilityMapLocation) => {
95
96
97
98
99
100
101
        const {interactive = true} = this.props;
        const oldSelectedLocation = this.state.selectedLocation;

        if (!interactive) {
            return;
        }

102
        this.setState({
103
104
            selectedLocation: oldSelectedLocation !== location ? location : null,
            center: location && location.location.coordinate_location.coordinates,
105
            zoom:  [17]
106
107
108
        });
    }

109
    render() {
110
        const {interactive = true} = this.props;
111
        const {maxBounds, facilityLocations, selectedLocation, center, zoom} = this.state;
112
        return (
113
            <this.Map
114
                onStyleLoad={(map: any) => {
115
116
117
118
119
120
121
122
123
124
                    if (interactive) {
                        map.addControl(new mapboxgl.GeolocateControl({
                            positionOptions: {
                                enableHighAccuracy: true
                            },
                            trackUserLocation: true
                        }));
                    }
                }}
                animationOptions={{
125
                    animate: true,
126
                    duration: 1250
127
128
                }}
                style="mapbox://styles/mduffy8/cjbcdxi3v73hp2spiyhxbkjde"
129
                movingMethod="easeTo"
130
131
132
133
134
135
136
                containerStyle={{
                    height: '100%',
                    width: '100%',
                    borderRadius: '5px',
                    cursor: 'pointer'
                }}
                center={center}
137
                fitBounds={maxBounds}
138
139
                zoom={zoom}
                maxBounds={maxBounds}>
140
141
142
143
144
145
146

                {interactive &&
                (
                    <FormControl className={'facilities-map-campus-select'}>
                        <Select
                            disableUnderline
                            value={this.state.campusRegion}
147
148
149
150
151
                            onChange={(e) => this.changeRegion((CampusRegion as any)[e.target.value])}>
                            <MenuItem value={CampusRegion.Fairfax}>Fairfax</MenuItem>
                            <MenuItem value={CampusRegion.Arlington}>Arlington</MenuItem>
                            <MenuItem value={CampusRegion.PrinceWilliam}>SciTech</MenuItem>
                            <MenuItem value={CampusRegion.FrontRoyal}>Front Royal</MenuItem>
152
153
154
155
                        </Select>
                    </FormControl>
                )}

156
157
158
                {(facilityLocations.length > 0) && facilityLocations.map((item) => {
                    const location = item.location;

159
160
                    return (
                        <Marker
161
162
163
164
165
                            key={location.id}
                            coordinates={location.coordinate_location.coordinates}
                            anchor="bottom"
                            onClick={() => this.selectLocation(item)}>
                            <div style={Mark} />
166
167
168
                        </Marker>
                    );
                })}
169
170
171
172

                {selectedLocation && (
                    <Popup coordinates={selectedLocation.location.coordinate_location.coordinates} anchor="top">
                        <div>
173
                            <Typography variant="subtitle1" align={'center'}>
174
175
176
177
178
179
180
181
                                {selectedLocation.location.building}
                            </Typography>
                        </div>
                        <div>
                            <ul className={'facilities-map-popup-list'}>
                                {selectedLocation.facilities.map((facility) => {
                                    return (
                                        <li key={facility.slug}>
182
                                            <Typography variant="caption">{removeBrackets(facility.facility_name)}</Typography>
183
184
185
186
187
188
189
                                        </li>
                                    );
                                })}
                            </ul>
                        </div>
                    </Popup>
                )}
190
            </this.Map>
191
        );
192
    }
193
}
194

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
export interface FacilitiesMapProps {
    facility: IFacility;
    facilities: IFacility[];
    interactive: boolean;

}

interface FacilityMapLocation {
    location: IFacilityLocation;
    facilities: IFacility[];
}

export interface FacilitiesMapState {
    maxBounds: number[][];
    campusRegion: CampusRegion;
    zoom: number[];
    center: number[];
    facilityLocations: FacilityMapLocation[];
    selectedLocation: FacilityMapLocation;
    isLoaded: boolean;
}

217
export default FacilitiesMap;