PageSourceSearch

https://www.stlouisfed.org/-/media/base-themes/maps/scripts/component-map.js

js stlouisfed.org collected 2026-09-24 06:39:23 UTC 19,638 bytes, 469 lines download raw bytes

1XA.component.map = (function ($, document) {
2
3    "use strict";
4
5    var api = {},
6        maps = [],
7        searchEndpoint,
8        searchResultsSignatures = [],
9        key,
10        urlHelperModel,
11        apiModel,
12        queryModel,
13        mapsConnector,
14        scriptsLoaded = false,
15        initialize,
16        searchResults,
17        pushMapData,
18        resultsLoaded,
19        myLocationChanged,
20        myLocationData,
21        mapViews = [],
22        MapModel,
23        MapView;
24
25    resultsLoaded = function (data) {
26        searchResults = data;
27    };
28
29    myLocationChanged = function (data) {
30        myLocationData = data;
31    };
32
33    initialize = function () {
34        var i, mapsCount = maps.length;
35        for (i = 0; i < mapsCount; i++) {
36            //crate Backbone.js views - one view per component on the page
37            mapViews.push(new MapView({el: maps[i], model: new MapModel()}));
38        }
39        if (typeof (XA.component.search) !== "undefined") {
40            pushMapData();
41        }
42    };
43
44    pushMapData = function() {
45        var notInitializedMaps,
46            resultsExists = typeof searchResults !== "undefined",
47            myLocationExists = typeof myLocationData !== "undefined";
48
49        if (resultsExists || myLocationExists) {
50            //in case that results were loaded before initialization of view and model, trigger another event with
51            //previously loaded results
52            //this will happen just once - while initialization
53            //remember about checking if all maps are already rendered
54            notInitializedMaps = mapViews.filter(function (view) {
55                if (view.model.get("showed") === false) {
56                    return true;
57                }
58                return false;
59            });
60
61            if (notInitializedMaps.length > 0) {
62                setTimeout(pushMapData, 1000);
63            } else {
64                if (resultsExists) {
65                    XA.component.search.vent.trigger("internal-results-loaded", searchResults);
66                }
67                if (myLocationExists) {
68                    XA.component.search.vent.trigger("internal-my-location-coordinates-changed", myLocationData);
69                }
70            }
71        }
72    };
73
74    MapModel = Backbone.Model.extend({
75        defaults: {
76            dataProperties: {},
77            dynamicPoiList: [],
78            showed: false,
79            myLocation: ["", ""],
80            id: null,
81            loadMore: false
82        },
83        initialize: function() {
84            var sig = this.get("dataProperties").searchResultsSignature,
85                hash = queryModel.parseHashParameters(window.location.hash),
86                param = typeof (sig) !== "undefined" && sig !== "" ? sig + "_g" : "g";
87
88            if (typeof (XA.component.search) !== "undefined") {
89                XA.component.search.vent.on("results-loaded", this.updateDynamicPoiList.bind(this));
90                XA.component.search.vent.on("internal-results-loaded", this.updateDynamicPoiList.bind(this));
91                XA.component.search.vent.on("my-location-coordinates-changed", this.changeMyLocation.bind(this));
92                XA.component.search.vent.on("internal-my-location-coordinates-changed", this.changeMyLocation.bind(this));
93                XA.component.search.vent.on("hashChanged", this.hashChanged.bind(this));
94            }
95
96            if (hash.hasOwnProperty(param) && hash[param] !== "") {
97                //if Location Filter component is on the page it could already fill "g" hash parameter
98                this.set("myLocation", hash[param].split("|"));
99            }
100        },
101        getPoiVariant: function (poiTypeId, poiVariantId) {
102            var mapping = this.get("dataProperties").typeToVariantMapping,
103                typeId;
104
105            if (typeof poiTypeId !== "undefined" && poiTypeId != null) {
106                typeId = "{" + poiTypeId.toUpperCase() + "}";
107                if (mapping.hasOwnProperty(typeId)) {
108                    return mapping[typeId];
109                } else {
110                    return poiVariantId;
111                }
112            }
113            return poiVariantId;
114        },
115        updateDynamicPoiList: function(searchResults) {
116            var dynamicPoiList = [],
117                signature = this.get("dataProperties").searchResultsSignature,
118                geolocationData = searchResults.data.filter(function (result) {
119                    if (result.hasOwnProperty("Geospatial")) {
120                        return true;
121                    } else {
122                        return false;
123                    }
124                }),
125                i,
126                poi;
127
128            if (signature !== searchResults.searchResultsSignature) {
129                return;
130            }
131
132            //save information that those POIs comes from load more action
133            this.set("loadMore", searchResults.loadMore);
134
135            for (i = 0; i < geolocationData.length; i++) {
136                poi = geolocationData[i];
137
138                //don't show POIs which doesn't have Latitude and Longitude
139                if (poi.Geospatial.Latitude === 0 || poi.Geospatial.Longitude === 0) {
140                    continue;
141                }
142
143                dynamicPoiList.push({
144                    id: poi.Id,
145                    type: "Dynamic",
146                    title: poi.Name,
147                    latitude: poi.Geospatial.Latitude,
148                    longitude: poi.Geospatial.Longitude,
149                    icon: poi.Geospatial.PoiIcon,
150                    poiTypeId: poi.Geospatial.PoiTypeId,
151                    poiVariantId: this.getPoiVariant(poi.Geospatial.PoiTypeId, poi.Geospatial.PoiVariantId)
152                });
153            }
154
155            this.set("dynamicPoiList", dynamicPoiList);
156        },
157        changeMyLocation: function (myLocationData) {
158            var sig = this.get("dataProperties").searchResultsSignature;
159            if (sig === myLocationData.sig) {
160                this.set("myLocation", myLocationData.coordinates);
161            }
162        },
163        hashChanged: function (hash) {
164            var sig = this.get("dataProperties").searchResultsSignature,
165                location = hash[sig !== "" ? sig + "_g" : "g"],
166                myLocationDataSignature = typeof myLocationData !== "undefined" ? myLocationData.sig : "",
167                parts;
168
169            if (sig === myLocationDataSignature && typeof location !== "undefined" && location !== null && location !== "") {
170                parts = location.split("|");
171                if (parts.length > 1) {
172                    this.set("myLocation", [parts[0], parts[1]]);
173                }
174            }
175        }
176    });
177
178    MapView = Backbone.View.extend({
179        initialize : function () {
180            var dataProperties = this.$el.data(),
181                properties = dataProperties.properties;
182
183            if (this.model) {
184                this.model.set({dataProperties: properties});
185                this.model.set({id: this.$el.find(".map-canvas").prop("id")});
186            }
187
188            this.render();
189            this.model.on("change:dynamicPoiList", this.renderDynamicPois, this);
190            this.model.on("change:myLocation", this.updateMyLocationPoi, this);
191            if (typeof (XA.component.search) !== "undefined") {
192                XA.component.search.vent.on("center-map", this.handleCenterMap.bind(this));
193            }
194            this.updateMyLocationPoi();
195
196        },
197        render : function () {
198            var that = this,
199                showed = this.model.get("showed"),
200                canvas = document.getElementById(this.model.get("id"));
201
202            if (!showed && canvas !== null) {
203                this.getCentralPoint(function (viewBounds, ctx) {
204                    if (typeof viewBounds !== "undefined") {
205                        var context = typeof ctx !== "undefined" ? ctx : this,
206                            id = context.model.get("id"),
207                            properties = context.model.get("dataProperties"),
208                            mapOptions = {
209                                canvasId: id,
210                                zoom: typeof(properties.zoom) === "number" ? properties.zoom : context.parseZoom(properties.zoom, 15),
211                                mode: properties.mode,
212                                poiCount: properties.pois.length,
213                                key: properties.key,
214                                disableMapScrolling: properties.disableMapScrolling,
215                                disableMapZoomOnScroll: properties.disableMapZoomOnScroll
216                            };
217
218                        mapsConnector.showMap(id, mapOptions, viewBounds);
219                        context.renderPoiList(id, properties.pois);
220
221                        context.model.set("showed", true);
222                    }
223                });
224            }
225        },
226        renderDynamicPois: function() {
227            var dataProperties = this.model.get("dataProperties"),
228                dynamicPoiList = this.model.get("dynamicPoiList"),
229                properties = this.model.get("dataProperties"),
230                id = this.model.get("id"),
231                i;
232
233            if (!this.model.get("loadMore")) {
234                mapsConnector.clearMarkers(id);
235            }
236
237            for (i = 0; i < dynamicPoiList.length; i++) {
238                mapsConnector.renderDynamicPoi(id, dynamicPoiList[i], this.getGeoPoiContent.bind(this));
239            }
240
241            //if user want to see all POIs then after adding dynamic POIs we have to recalculate map center point
242            if (dataProperties.centralPointMode === "MidOfPoi") {
243                mapsConnector.updateMapPosition(this.model.get("id"), this.parseZoom(properties.zoom, 15));
244            }
245        },
246        renderPoiList: function(mapId, poiList) {
247            var i,
248                poi,
249                myLocation,
250                poiCount = poiList.length,
251                properties = this.model.get("dataProperties"),
252                sig = properties.searchResultsSignature,
253                hash = queryModel.parseHashParameters(window.location.hash),
254                param = sig !== "" ? sig + "_g" : "g";
255
256            for (i = 0; i < poiCount; i++) {
257                poi = poiList[i];
258
259                if (poi.Type === "MyLocation") {
260                    myLocation = this.model.get("myLocation");
261                    poi.Latitude = myLocation[0];
262                    poi.Longitude = myLocation[1];
263
264                    if (!hash.hasOwnProperty(param) || (hash.hasOwnProperty(param) && hash[param] === "")) {
265                        //if there is no "g" param then it's mean that there is no Location Filter on the map
266                        //in this case we have take coordinated from the browser to display My Location POI
267                        this.getCurrentPosition(function (coordinates) {
268                            this.model.set("myLocation", coordinates);
269                        });
270                    } else if (hash.hasOwnProperty(param)) {
271                        this.model.set("myLocation", hash[param].split("|"));
272                    }
273                } else if (poi.Latitude === "" || poi.Longitude === "") {
274                    continue;
275                }
276
277                mapsConnector.renderPoi(mapId, {
278                    id: poi.Id.Guid,
279                    title: poi.Title,
280                    description: poi.Description,
281                    latitude: poi.Latitude,
282                    longitude: poi.Longitude,
283                    icon: poi.PoiIcon,
284                    html: poi.Html,
285                    type: poi.Type
286                });
287            }
288        },
289        getPoiContent: function(poiId, poiTypeId, poiVariantId, renderPoiContentCallback) {
290            var properties = this.model.get("dataProperties"),
291                url = urlHelperModel.createGetPoiContentUrl({endpoint: properties.variantsEndpoint}, poiId, poiVariantId);
292
293            apiModel.getData({
294                callback: renderPoiContentCallback,
295                url: url,
296                excludeSiteName: true
297            });
298        },
299        getGeoPoiContent: function (poiId, poiTypeId, poiVariantId, renderPoiContentCallback) {
300            var myLocation = this.model.get("myLocation"),
301                latitude = myLocation[0],
302                longitude = myLocation[1],
303                properties = this.model.get("dataProperties"),
304                hash = queryModel.parseHashParameters(window.location.hash),
305                units = hash.o,
306                url = urlHelperModel.createGetGeoPoiContentUrl({ endpoint: properties.variantsEndpoint }, poiId, poiVariantId, latitude + "," + longitude, units, properties.itemId);
307
308            apiModel.getData({
309                callback: renderPoiContentCallback,
310                url: url,
311                excludeSiteName: true
312            });
313
314        },
315        getCentralPoint: function (callback) {
316            var properties = this.model.get("dataProperties"),
317                that = this;
318
319            switch (properties.centralPointMode) {
320                case "Auto": {
321                    if (properties.centralPoint !== "") {
322                        callback.call(that, [properties.latitude, properties.longitude]);
323                    } else if (properties.pois.length > 0) {
324                        callback.call(that, [properties.pois[0].Latitude, properties.pois[0].Longitude]);
325                    } else {
326                        this.getCurrentPosition(callback);
327                    }
328                    break;
329                }
330                case "MidOfPoi": {
331                    callback.call(that, this.getPoisCentralPoint());
332                    break;
333                }
334                case "Location":{
335                    this.getCurrentPosition(callback);
336                    break;
337                }
338            }
339        },
340        getCurrentPosition: function (callback) {
341          var that = this;
342          XA.component.locationService.detectLocation(
343              function (location) {
344                  callback.call(that, location, that);
345              },
346              function (errorMessage) {
347                  callback.call(that, [0, 0], that);
348                  console.log(errorMessage);
349              }
350          );
351        },
352        getPoisCentralPoint: function () {
353            var i,
354                poi,
355                poisCoords = [],
356                myLocation = this.model.get("myLocation"),
357                properties = this.model.get("dataProperties"),
358                count = properties.pois.length;
359
360            for (i = 0; i < count; i++) {
361                poi = properties.pois[i];
362                if (poi.TemplateId.Guid === "7dd9ece5-9461-498d-8721-7cbea8111b5e") {
363                    if (myLocation[0] !== "" && myLocation[1] !== "") {
364                        poi.Latitude = myLocation[0];
365                        poi.Longitude = myLocation[1];
366                        this.model.set("dataProperties", properties);
367                        poisCoords.push({latitude: poi.Latitude, longitude: poi.Longitude});
368                    }
369                } else {
370                    poisCoords.push({latitude: poi.Latitude, longitude: poi.Longitude});
371                }
372            }
373
374            return mapsConnector.getCentralPoint(poisCoords);
375        },
376        handleCenterMap: function (data) {
377            var centerMap = this.model.get("dataProperties").centerOnFoundPoi === "1",
378                animate = this.model.get("dataProperties").animateFoundPoi === "1";
379            this.centerOnMap(data, centerMap, animate);
380        },
381        centerOnMap: function (data, centerMap, animate) {
382            if (data.sig === this.model.get("dataProperties").searchResultsSignature) {
383                mapsConnector.centerMap(this.model.get("id"), data, centerMap, animate);
384            }
385        },
386        updateMyLocationPoi: function () {
387            var properties = this.model.get("dataProperties"),
388                myLocation = this.model.get("myLocation");
389
390            //check if there is something in my location
391            if (myLocation[0] !== "" && myLocation[1] !== 0) {
392                //my location was changed so update position of My Location marker
393                mapsConnector.updateMyPoiLocation(this.model.get("id"), myLocation, this.parseZoom(properties.zoom, 15));
394            } else if (properties.latitude !== "" && properties.longitude !== "") {
395                var data = {};
396                data.sig = properties.searchResultsSignature;
397                data.coordinates = [properties.latitude, properties.longitude];
398                this.centerOnMap(data, true, false);
399            }
400        },
401        parseZoom: function (str, defaultValue) {
402            var retValue = defaultValue;
403            if(str !== null) {
404                if(str.length > 0) {
405                    if (!isNaN(str)) {
406                        retValue = parseInt(str);
407                    }
408                }
409            }
410            return retValue;
411        }
412    });
413
414    api.init = function() {
415        var i,
416            mapElements = $(".map.component:not(.initialized)"),
417            count = mapElements.length;
418
419        if (typeof (XA.component.search) !== "undefined") {
420            queryModel = XA.component.search.query;
421            urlHelperModel = XA.component.search.url;
422            apiModel = XA.component.search.ajax;
423
424            //if the page was reloaded there could be situation that search results will load results faster then map initialization
425            //so that we have to save them and pass to the models when they will be created
426            XA.component.search.vent.on("results-loaded", resultsLoaded);
427            //the same with "my location", sometimes Location Filter component can change location before map was initialized
428            XA.component.search.vent.on("my-location-coordinates-changed", myLocationChanged);
429        }
430        mapsConnector = XA.connector.mapsConnector;
431
432        if (count > 0) {
433            for (i = 0; i < count; i++) {
434                var $map = $(mapElements[i]);
435                var properties = $map.data("properties");
436                key = properties.key;
437                searchEndpoint = properties.endpoint;
438                searchResultsSignatures.push(properties.searchResultsSignature)
439                $map.addClass("initialized");
440                maps.push($map);
441            }
442
443            if (!scriptsLoaded) {
444                mapsConnector.loadScript(key, XA.component.map.scriptsLoaded);
445            } else {
446                initialize();
447            }
448        }
449    };
450
451    api.                                                scriptsLoaded = function() {
452        console.log("Maps api loaded");
453        scriptsLoaded = true;
454        initialize();
455    };
456
457    api.getSearchEndpoint = function() {
458        return searchEndpoint;
459    };
460
461    api.getSignatures = function() {
462        return searchResultsSignatures;
463    }
464
465    return api;
466
467}(jQuery, document));
468
469XA.register("map", XA.component.map);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.