This repository has been archived by the owner on Mar 29, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathindex.js
140 lines (122 loc) · 4.3 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* global google */
import React from 'react';
import ReactDOM from 'react-dom';
import GoogleMaps from './src/GoogleMaps.js';
import instantsearch from 'instantsearch.js';
/**
* algolia/instantsearch.js widget to display your Algolia geo hits on a map using Google Maps APIs
* @param {DOMElement} options.container Where to insert the map in the document. This is required.
* @param {function} [options.prepareMarkerData] Function Called for every hit,
* this is the moment where you can select the label and title
* for the marker. This function should return an object in the form of `{label, title}`.
*
* Example:
*
* ```js
* function prepareMarkerData(hit, index, hits) {
* return {
* label: hit.name,
* title: hit.description
* }
* }
* ```
*
* The `label` first letter will be displayed on the marker on the map.
*
* The `title` will be displayed when hovering the marker.
*
* By default we use the current hit index in the results as the label and the hit `ObjectID` for the title.
* when hovering the marker
* @param {boolean} [options.refineOnMapInteraction=false] Should we refine the search
* on map interaction, default to false
* @return {Object}
*/
function googleMaps({
container,
refineOnMapInteraction = false,
prepareMarkerData = (hit, index) => ({
label: `${index}`,
title: hit.objectID
})
}) {
let widget = {
_refine({helper}, userRefine) {
let p1 = userRefine.bounds.getNorthEast();
let p2 = userRefine.bounds.getSouthWest();
let box = [p1.lat(), p1.lng(), p2.lat(), p2.lng()];
this._lastUserRefine = userRefine;
helper
.setQueryParameter('insideBoundingBox', box.join(','))
.search()
.setQueryParameter('insideBoundingBox', undefined);
},
render({results, helper}) {
let zoom;
let center;
let markers = results.hits
.filter(hit => hit._geoloc !== undefined)
.map((hit, index) =>
({
position: new google.maps.LatLng(hit._geoloc),
id: hit.objectID,
...prepareMarkerData(hit, index, results.hits)
})
);
if (markers.length === 0) {
zoom = 1;
center = new google.maps.LatLng({
lat: 48.797885,
lng: 2.337034
});
} else if (this._lastUserRefine) {
zoom = this._lastUserRefine.zoom;
center = this._lastUserRefine.center;
this._lastUserRefine = false;
} else {
let bounds = new google.maps.LatLngBounds();
markers.forEach(marker => bounds.extend(marker.position));
zoom = this._getBestZoomLevel(bounds, container.getBoundingClientRect());
center = bounds.getCenter();
}
ReactDOM.render(
<GoogleMaps
center={center}
markers={markers}
refine={this._refine.bind(this, {helper})}
refineOnMapInteraction={refineOnMapInteraction}
zoom={zoom}
/>, container
);
},
// http://stackoverflow.com/a/13274361/147079
// We cannot use map.fitBounds because we are in a React world
// where you should not (and it does not works) try to modify
// the rendering once rendered
// You need to recompute the right props
// It's actually a lot easier than the previous implementation
// that was using a LOT of state
_getBestZoomLevel(bounds, mapDim) {
const WORLD_DIM = {height: 256, width: 256};
const ZOOM_MAX = 21;
function latRad(lat) {
var sin = Math.sin(lat * Math.PI / 180);
var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
function zoom(mapPx, worldPx, fraction) {
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
}
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;
var lngDiff = ne.lng() - sw.lng();
var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);
return Math.min(latZoom, lngZoom, ZOOM_MAX);
}
};
return widget;
}
instantsearch.widgets.googleMaps = googleMaps;
export default googleMaps;