mapicgc-gl-js 1.0.2 → 1.0.3

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/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "mapicgc-gl-js",
3
3
  "homepage": "https://openicgc.github.io/mapicgc-doc/",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "description": "mapicgc-gl-js library",
6
6
  "author": "Institut Cartogràfic i Geològic de Catalunya",
7
7
  "license": "BSD-3-Clause",
8
8
  "type": "commonjs",
9
-
10
9
  "keywords": [
11
10
  "map",
12
11
  "js",
@@ -43,34 +42,34 @@
43
42
  "test": "vitest"
44
43
  },
45
44
  "devDependencies": {
46
- "@babel/core": "^7.28.5",
47
- "@babel/preset-env": "^7.28.5",
48
- "@rollup/plugin-babel": "^6.1.0",
49
- "axios": "^1.13.1",
50
- "dotenv": "^17.2.3",
51
- "jest": "30.2.0",
45
+ "@babel/core": "^7.29.0",
46
+ "@babel/preset-env": "^7.29.2",
47
+ "@rollup/plugin-babel": "^7.0.0",
48
+ "axios": "^1.14.0",
49
+ "dotenv": "^17.3.1",
50
+ "jest": "30.3.0",
52
51
  "jsdoc": "^4.0.5",
53
- "jsdom": "^27.0.1",
52
+ "jsdom": "^29.0.1",
54
53
  "npm-run-all": "^4.1.5",
55
54
  "package-json-versionify": "^1.0.4",
56
55
  "path": "^0.12.7",
57
56
  "rollup-plugin-polyfill": "^4.2.0",
58
- "ssh2-sftp-client": "^12.0.1",
59
- "vite": "^7.1.12",
60
- "vite-plugin-node-polyfills": "^0.24.0",
61
- "vitest": "^4.0.5",
57
+ "ssh2-sftp-client": "^12.1.1",
58
+ "vite": "^8.0.3",
59
+ "vite-plugin-node-polyfills": "^0.26.0",
60
+ "vitest": "^4.1.2",
62
61
  "xml2js": "^0.6.2"
63
62
  },
64
63
  "dependencies": {
65
- "@deck.gl/core": "^9.2.2",
66
- "@deck.gl/geo-layers": "^9.2.2",
67
- "@deck.gl/mapbox": "^9.2.2",
64
+ "@deck.gl/core": "^9.2.11",
65
+ "@deck.gl/geo-layers": "^9.2.11",
66
+ "@deck.gl/mapbox": "^9.2.11",
68
67
  "@loaders.gl/3d-tiles": "~4.3.4",
69
68
  "@maplibre/maplibre-gl-compare": "^0.5.0",
70
- "@maplibre/maplibre-gl-geocoder": "^1.9.1",
71
- "@watergis/maplibre-gl-export": "^4.1.0",
72
- "flatgeobuf": "^4.3.1",
73
- "maplibre-gl": "^5.10.0",
69
+ "@maplibre/maplibre-gl-geocoder": "^1.9.4",
70
+ "@watergis/maplibre-gl-export": "^4.1.2",
71
+ "flatgeobuf": "^4.4.0",
72
+ "maplibre-gl": "^5.21.1",
74
73
  "utm-latlng": "^1.0.8"
75
74
  }
76
75
  }
package/src/map/Map.js CHANGED
@@ -178,6 +178,7 @@ export default class Map {
178
178
  }
179
179
 
180
180
  this.map.on("load", () => {
181
+ this.addAttributionControl()
181
182
  if (!isRaster && !isRelief) {
182
183
  const nameStyle = this.map.getStyle().name;
183
184
  const urlName = options.style;
@@ -2846,14 +2847,43 @@ export default class Map {
2846
2847
  }
2847
2848
  }
2848
2849
  /**
2849
- * Adds an attribution control to the map with the provided options.
2850
+ * Adds an attribution control to the map. Always includes "Fet amb MapICGC" attribution by default.
2851
+ * If additional custom attributions are provided, they will be combined with the default one.
2850
2852
  * @function addAttributionControl
2851
- * @param {Object} options - Options for the attribution control.
2853
+ * @param {Object} [options] - Options for the attribution control.
2854
+ * @param {boolean} [options.compact=true] - If true, the attribution control will be compact.
2855
+ * @param {string|string[]} [options.customAttribution] - Additional custom attribution(s) to display alongside "Fet amb MapICGC".
2852
2856
  * @param {string} [position='bottom-right'] - Position to add the control on the map.
2857
+ * @example
2858
+ * // Default usage: shows "Fet amb MapICGC" with compact mode
2859
+ * map.addAttributionControl();
2860
+ *
2861
+ * // With additional custom attribution
2862
+ * map.addAttributionControl({ customAttribution: '© El meu projecte' });
2863
+ *
2864
+ * // With multiple custom attributions
2865
+ * map.addAttributionControl({ customAttribution: ['© Projecte A', '© Projecte B'] });
2853
2866
  */
2854
2867
  addAttributionControl(options, position) {
2855
2868
  try {
2856
- this.map.addControl(new maplibregl.AttributionControl(options), position);
2869
+ const mapicgcAttribution = '<a style="font-weight: bold; color: #D97634;" href="https://www.icgc.cat/Eines-i-visors/Recursos-desenvolupadors/Biblioteca-MapICGC-GL-JS/" target="_blank">Fet amb MapICGC</a>';
2870
+ const mergedOptions = Object.assign({}, { compact: true }, options);
2871
+
2872
+ if (mergedOptions.customAttribution) {
2873
+ if (Array.isArray(mergedOptions.customAttribution)) {
2874
+ if (!mergedOptions.customAttribution.includes(mapicgcAttribution)) {
2875
+ mergedOptions.customAttribution = [mapicgcAttribution, ...mergedOptions.customAttribution];
2876
+ }
2877
+ } else {
2878
+ if (mergedOptions.customAttribution !== mapicgcAttribution) {
2879
+ mergedOptions.customAttribution = [mapicgcAttribution, mergedOptions.customAttribution];
2880
+ }
2881
+ }
2882
+ } else {
2883
+ mergedOptions.customAttribution = mapicgcAttribution;
2884
+ }
2885
+
2886
+ this.map.addControl(new maplibregl.AttributionControl(mergedOptions), position);
2857
2887
  } catch (error) {
2858
2888
  console.error(`Error adding attribution control: ${error.message}`);
2859
2889
  }
@@ -39,13 +39,15 @@
39
39
 
40
40
  map.on("load", () => {
41
41
  map.flyTo({
42
- center: [2.812786, 41.98559],
43
- zoom: 14,
42
+ center: [2.812786, 41.98559],
43
+ zoom: 14,
44
+ });
44
45
 
45
- });
46
-
47
- });
46
+
47
+ });
48
48
  }
49
+
50
+
49
51
  initMap();
50
52
  </script>
51
53
  </body>
@@ -0,0 +1,145 @@
1
+ import { describe, expect, test, vi, beforeEach } from 'vitest';
2
+
3
+ // Mock axios before importing Config
4
+ vi.mock('axios', () => ({
5
+ default: {
6
+ get: vi.fn(),
7
+ },
8
+ }));
9
+
10
+ import axios from 'axios';
11
+ import mapicgcConfig from '../../src/mapicgc-config.json';
12
+
13
+ // Import Config after mocking axios
14
+ import Config from '../../src/constants/ConfigICGC.js';
15
+
16
+ describe('ConfigICGC', () => {
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ test('should export a Config class with getConfigICGC static method', () => {
22
+ expect(Config).toBeDefined();
23
+ expect(typeof Config.getConfigICGC).toBe('function');
24
+ });
25
+
26
+ test('should return remote config data when API responds successfully', async () => {
27
+ const mockRemoteConfig = {
28
+ Styles: { TOPO: 'https://example.com/topo.json' },
29
+ Layers: { WMS: {} },
30
+ Terrains: {},
31
+ defaultOptions: { mapOptions: {} },
32
+ };
33
+
34
+ axios.get.mockResolvedValueOnce({ data: mockRemoteConfig });
35
+
36
+ const result = await Config.getConfigICGC();
37
+
38
+ expect(axios.get).toHaveBeenCalledTimes(1);
39
+ expect(axios.get).toHaveBeenCalledWith(
40
+ 'https://eines.icgc.cat/recursos/mapicgc-gl-js/mapicgc-config.json',
41
+ { timeout: 5000 }
42
+ );
43
+ expect(result).toEqual(mockRemoteConfig);
44
+ });
45
+
46
+ test('should return local mapicgc-config.json when API returns empty data', async () => {
47
+ axios.get.mockResolvedValueOnce({ data: null });
48
+
49
+ const result = await Config.getConfigICGC();
50
+
51
+ expect(result).toEqual(mapicgcConfig);
52
+ });
53
+
54
+ test('should return local mapicgc-config.json when API call fails with network error', async () => {
55
+ axios.get.mockRejectedValueOnce(new Error('Network Error'));
56
+
57
+ const result = await Config.getConfigICGC();
58
+
59
+ expect(result).toEqual(mapicgcConfig);
60
+ });
61
+
62
+ test('should return local mapicgc-config.json when API returns HTTP error', async () => {
63
+ const httpError = new Error('Request failed');
64
+ httpError.response = { data: 'Not Found', status: 404 };
65
+ axios.get.mockRejectedValueOnce(httpError);
66
+
67
+ const result = await Config.getConfigICGC();
68
+
69
+ expect(result).toEqual(mapicgcConfig);
70
+ });
71
+
72
+ test('should return local mapicgc-config.json when server does not respond (timeout)', async () => {
73
+ const timeoutError = new Error('Timeout');
74
+ timeoutError.request = {};
75
+ axios.get.mockRejectedValueOnce(timeoutError);
76
+
77
+ const result = await Config.getConfigICGC();
78
+
79
+ expect(result).toEqual(mapicgcConfig);
80
+ });
81
+ });
82
+
83
+ describe('mapicgc-config.json structure', () => {
84
+ test('should have defaultOptions with mapOptions', () => {
85
+ expect(mapicgcConfig.defaultOptions).toBeDefined();
86
+ expect(mapicgcConfig.defaultOptions.mapOptions).toBeDefined();
87
+ });
88
+
89
+ test('should have mapOptions with required fields', () => {
90
+ const mapOpts = mapicgcConfig.defaultOptions.mapOptions;
91
+ expect(mapOpts.container).toBeDefined();
92
+ expect(mapOpts.center).toBeDefined();
93
+ expect(mapOpts.zoom).toBeDefined();
94
+ expect(mapOpts.style).toBeDefined();
95
+ expect(mapOpts.maxZoom).toBeDefined();
96
+ });
97
+
98
+ test('should have center coordinates for Catalonia', () => {
99
+ const center = mapicgcConfig.defaultOptions.mapOptions.center;
100
+ // Catalonia approx: lon 0.15-3.33, lat 40.5-42.9
101
+ const lon = center['0'] || center[0];
102
+ const lat = center['1'] || center[1];
103
+ expect(lon).toBeGreaterThan(0);
104
+ expect(lon).toBeLessThan(4);
105
+ expect(lat).toBeGreaterThan(40);
106
+ expect(lat).toBeLessThan(43);
107
+ });
108
+
109
+ test('should have Styles configuration', () => {
110
+ expect(mapicgcConfig.Styles).toBeDefined();
111
+ expect(Array.isArray(mapicgcConfig.Styles) || typeof mapicgcConfig.Styles === 'object').toBe(true);
112
+ });
113
+
114
+ test('should have Layers configuration with WMS, Orto, Vector', () => {
115
+ expect(mapicgcConfig.Layers).toBeDefined();
116
+ expect(mapicgcConfig.Layers.WMS).toBeDefined();
117
+ expect(mapicgcConfig.Layers.Orto).toBeDefined();
118
+ expect(mapicgcConfig.Layers.Vector).toBeDefined();
119
+ });
120
+
121
+ test('should have Terrains configuration', () => {
122
+ expect(mapicgcConfig.Terrains).toBeDefined();
123
+ });
124
+
125
+ test('should have geocoder config with pelias URLs', () => {
126
+ const geocoder = mapicgcConfig.defaultOptions.geocoder;
127
+ expect(geocoder).toBeDefined();
128
+ expect(geocoder.peliasUrl1).toBeDefined();
129
+ expect(geocoder.peliasUrl1).toContain('icgc.cat');
130
+ });
131
+
132
+ test('should have logo ICGC options', () => {
133
+ const logo = mapicgcConfig.defaultOptions.logoIcgcOptions;
134
+ expect(logo).toBeDefined();
135
+ expect(logo.logoUrlColor).toBeDefined();
136
+ expect(logo.logoLink).toContain('icgc.cat');
137
+ });
138
+
139
+ test('should have map3d options', () => {
140
+ const opts3d = mapicgcConfig.defaultOptions.map3dOptions;
141
+ expect(opts3d).toBeDefined();
142
+ expect(opts3d.exaggeration).toBeDefined();
143
+ expect(opts3d.terrainSource).toBeDefined();
144
+ });
145
+ });