radar-sdk-js 4.2.1-beta.2 → 4.3.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ui/map.ts CHANGED
@@ -1,157 +1,23 @@
1
1
  import maplibregl from 'maplibre-gl';
2
2
 
3
- import Config from '../config';
4
- import Logger from '../logger';
3
+ import RadarMap from './RadarMap';
4
+ import RadarMarker from './RadarMarker';
5
5
 
6
- import type { RadarOptions, RadarMapOptions, RadarMarkerOptions } from '../types';
7
-
8
- const DEFAULT_STYLE = 'radar-default-v1';
9
-
10
- const RADAR_STYLES = [
11
- 'radar-default-v1',
12
- 'radar-light-v1',
13
- 'radar-dark-v1',
14
- ];
15
-
16
- const RADAR_LOGO_URL = 'https://api.radar.io/maps/static/images/logo.svg';
17
-
18
- const defaultMaplibreOptions: Partial<maplibregl.MapOptions> = {
19
- minZoom: 1,
20
- maxZoom: 20,
21
- attributionControl: false,
22
- dragRotate: false,
23
- touchPitch: false,
24
- maplibreLogo: false,
25
- };
26
-
27
- const defaultMarkerOptions: Partial<maplibregl.MarkerOptions> = {
28
- color: '#000257',
29
- };
30
-
31
- const createStyleURL = (options: RadarOptions, style: string = DEFAULT_STYLE) => (
32
- `${options.host}/maps/styles/${style}?publishableKey=${options.publishableKey}`
33
- );
34
-
35
- // use formatted style URL if using one of Radar's out-of-the-box styles
36
- const getStyle = (options: RadarOptions, mapOptions: RadarMapOptions) => {
37
- const style = mapOptions.style;
38
-
39
- if (!style || (typeof style === 'string' && RADAR_STYLES.includes(style))) {
40
- return createStyleURL(options, mapOptions.style as string);
41
- }
42
-
43
- return mapOptions.style;
44
- };
6
+ import type { RadarMapOptions, RadarMarkerOptions } from '../types';
45
7
 
46
8
  class MapUI {
47
9
  public static getMapLibre() {
48
10
  return maplibregl;
49
11
  }
50
12
 
51
- public static createMap(mapOptions: RadarMapOptions): maplibregl.Map {
52
- const options = Config.get();
53
-
54
- if (!options.publishableKey) {
55
- Logger.warn('publishableKey not set. Call Radar.initialize() with key before creating a new map.');
56
- }
57
-
58
- // configure maplibre options
59
- const style = getStyle(options, mapOptions);
60
- const maplibreOptions: maplibregl.MapOptions = Object.assign({},
61
- defaultMaplibreOptions,
62
- mapOptions,
63
- { style },
64
- );
65
- Logger.debug(`initialize map with options: ${JSON.stringify(maplibreOptions)}`);
66
-
67
- // set container
68
- maplibreOptions.container = mapOptions.container;
69
-
70
- // custom request handler for Radar styles
71
- maplibreOptions.transformRequest = (url, resourceType) => {
72
- if (resourceType === 'Style' && RADAR_STYLES.includes(url)) {
73
- const radarStyleURL = createStyleURL(options, url);
74
- return { url: radarStyleURL };
75
- } else {
76
- return { url };
77
- }
78
- };
79
-
80
- // create map
81
- const map = new maplibregl.Map(maplibreOptions);
82
- const container = map.getContainer();
83
-
84
- if (!container.style.width && !container.style.height) {
85
- Logger.warn('map container does not have a set "width" or "height"');
86
- }
87
-
88
- // add radar logo
89
- const img = document.createElement('img');
90
- img.src = RADAR_LOGO_URL;
91
-
92
- const link = document.createElement('a');
93
- link.id = 'radar-map-logo';
94
- link.href = 'https://radar.com?ref=powered_by_radar';
95
- link.target = '_blank';
96
- link.style.position = 'absolute';
97
- link.style.bottom = '0';
98
- link.style.left = '5px';
99
- link.style.width = '80px';
100
- link.style.height = '38px';
101
- link.appendChild(img)
102
- map.getContainer().appendChild(link);
103
-
104
- // add attribution
105
- const attribution = new maplibregl.AttributionControl({ compact: false });
106
- map.addControl(attribution, 'bottom-right');
107
-
108
- // add zoom controls
109
- const nav = new maplibregl.NavigationControl({ showCompass: false });
110
- map.addControl(nav, 'bottom-right');
111
-
112
- // handle map resize actions
113
- const onResize = () => {
114
- const attrib = document.querySelector('.maplibregl-ctrl-attrib');
115
- if (attrib) {
116
- const width = map.getContainer().clientWidth;
117
- if (width < 380) {
118
- attrib.classList.add('hidden');
119
- } else {
120
- attrib.classList.remove('hidden');
121
- }
122
- }
123
- };
124
- map.on('resize', onResize);
125
- map.on('load', onResize);
126
-
127
- return map;
13
+ public static createMap(mapOptions: RadarMapOptions): RadarMap {
14
+ const radarMap = new RadarMap(mapOptions);
15
+ return radarMap;
128
16
  }
129
17
 
130
- public static createMarker(markerOptions: RadarMarkerOptions = {}): maplibregl.Marker {
131
- const maplibreOptions: maplibregl.MarkerOptions = Object.assign({}, defaultMarkerOptions);
132
-
133
- if (markerOptions.color) {
134
- maplibreOptions.color = markerOptions.color;
135
- }
136
- if (markerOptions.element) {
137
- maplibreOptions.element = markerOptions.element;
138
- }
139
- if (markerOptions.scale) {
140
- maplibreOptions.scale = markerOptions.scale;
141
- }
142
-
143
- const marker = new maplibregl.Marker(maplibreOptions);
144
-
145
- // set popup text or HTML
146
- if (markerOptions.text) {
147
- const popup = new maplibregl.Popup({ offset: 35 }).setText(markerOptions.text);
148
- marker.setPopup(popup);
149
- } else if (markerOptions.html) {
150
- const popup = new maplibregl.Popup({ offset: 35 }).setHTML(markerOptions.html);
151
- marker.setPopup(popup);
152
- }
153
-
154
- return marker;
18
+ public static createMarker(markerOptions: RadarMarkerOptions = {}): RadarMarker {
19
+ const radarMarker = new RadarMarker(markerOptions);
20
+ return radarMarker;
155
21
  }
156
22
  }
157
23
 
package/src/util/_.ts ADDED
@@ -0,0 +1,30 @@
1
+ //check if value is primitive
2
+ const isPrimitive = (obj: any) => {
3
+ return (obj !== Object(obj));
4
+ }
5
+
6
+ export const deepEqual = (obj1: any, obj2: any) => {
7
+
8
+ if (obj1 === obj2) // it's just the same object. No need to compare.
9
+ return true;
10
+
11
+ if (isPrimitive(obj1) && isPrimitive(obj2)) // compare primitives
12
+ return obj1 === obj2;
13
+
14
+ if (Object.keys(obj1).length !== Object.keys(obj2).length)
15
+ return false;
16
+
17
+ // compare objects with same number of keys
18
+ for (let key in obj1) {
19
+ if (!(key in obj2)) return false; //other object doesn't have this prop
20
+ if (!deepEqual(obj1[key], obj2[key])) return false;
21
+ }
22
+
23
+ return true;
24
+ }
25
+
26
+ export const uniq = <T extends any>(arr: T[]): T[] => {
27
+ const outputArray: T[] = arr.filter((v, i, self) => i === self.indexOf(v));
28
+
29
+ return outputArray;
30
+ }
@@ -0,0 +1,85 @@
1
+ import * as _ from './_';
2
+
3
+ import Logger from '../logger';
4
+
5
+ import { RadarMapOptions } from '../types';
6
+
7
+ // NOTE(jasonl): ENSURE THIS STAYS IN SYNC WITH THE SERVER IMPLEMENTATION
8
+ const RADAR_LANGUAGE_EXPR = ['get', 'radar:name_client_language'];
9
+
10
+ /** get an array of languages set in the browser in RFC 5646 format */
11
+ const getBrowserLanguages = (options = { fallback: 'en', format: 'RFC-5646' }) => {
12
+ let languagesRFC5646 = [options.fallback];
13
+ if (navigator.languages.length > 0) {
14
+ languagesRFC5646 = [...navigator.languages];
15
+ } else if (navigator.language) {
16
+ languagesRFC5646 = [navigator.language];
17
+ }
18
+
19
+ if (options.format === 'ISO-639-1') {
20
+ // RFC 5646 format is always prefixed by the ISO 639-1 language code so we need to strip that out
21
+ const languagesISO6391 = _.uniq(languagesRFC5646.map(l => l.split('-')[0]));
22
+ return languagesISO6391;
23
+ }
24
+
25
+ return languagesRFC5646;
26
+ };
27
+
28
+ const replaceAllValuesInExpression = (expr: any, target: any[], value: any[]): any => {
29
+ if (target.length !== value.length) {
30
+ Logger.warn('replaceAllValueInExpression: Target and value arrays must be the same length');
31
+ return expr;
32
+ }
33
+
34
+ const findIndex = target.findIndex((t) => _.deepEqual(t, expr));
35
+ if (findIndex !== -1) {
36
+ return value[findIndex];
37
+ }
38
+
39
+ if (Array.isArray(expr)) {
40
+ return expr.map((e) => replaceAllValuesInExpression(e, target, value));
41
+ }
42
+
43
+ return expr;
44
+ };
45
+
46
+ export const transformMapStyle = (styleJSON: any, options: Pick<RadarMapOptions, 'languages' | 'navigatorFallbackLanguage'>): any => {
47
+ let languages: string[] = [];
48
+
49
+ // use browser language if style language is set to local
50
+ if (styleJSON?.metadata?.['radar:language'] === 'local') {
51
+ const fallbackLanguage = options.navigatorFallbackLanguage || 'en';
52
+ languages = getBrowserLanguages({ fallback: fallbackLanguage, format: 'ISO-639-1' });
53
+ }
54
+
55
+ // client set language takes precedence
56
+ if (options.languages) {
57
+ languages = options.languages;
58
+ }
59
+
60
+ if (languages.length > 0) {
61
+ // construct expression ordered by language preference
62
+ const localLanguageExpression: any[] = ['coalesce'];
63
+ languages.forEach((l: any) => {
64
+ localLanguageExpression.push(['get', `name_${l}`], ['get', `name:${l}`]);
65
+ });
66
+
67
+ const transformedLayers = styleJSON.layers.map((layer: any) => {
68
+ if (layer.type === 'symbol' && layer.layout['text-field']) {
69
+ layer.layout['text-field'] = replaceAllValuesInExpression(
70
+ layer.layout['text-field'],
71
+ [RADAR_LANGUAGE_EXPR],
72
+ [localLanguageExpression]
73
+ );
74
+
75
+ return layer;
76
+ }
77
+
78
+ return layer;
79
+ });
80
+
81
+ return { ...styleJSON, layers: transformedLayers };
82
+ }
83
+
84
+ return styleJSON;
85
+ };
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '4.2.1-beta.2';
1
+ export default '4.3.0-beta.1';