Skip to content

Commit ceaf548

Browse files
committed
HPC-9963: WIP Replace leaflet with mapbox gl
1 parent e06e0b6 commit ceaf548

File tree

62 files changed

+5717
-1089
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+5717
-1089
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<IfModule mod_rewrite.c>
22
RewriteEngine on
33
SSLProxyEngine on
4-
#Add the string and keep hidden from user with [P]
4+
# Add the string and keep hidden from user with [P]
55
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)access_token=token(&.*)?$
66
RewriteRule ^/mapbox/(.*)$ https://api.mapbox.com/$1?%1access_token=${MAPBOX_TOKEN}%3 [P]
77
</IfModule>

config/seckit.settings.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ seckit_xss:
88
webkit: false
99
report-only: true
1010
default-src: "'none'"
11-
script-src: "'self' 'unsafe-inline' https://js-agent.newrelic.com https://static.addtoany.com browser-update.org/update.min.js https://bam.nr-data.net cdn.jsdelivr.net/npm/toastify-js https://unpkg.com/@popperjs/core@2 https://unpkg.com/tippy.js@6"
11+
script-src: "'self' 'unsafe-inline' https://js-agent.newrelic.com https://static.addtoany.com browser-update.org/update.min.js https://bam.nr-data.net cdn.jsdelivr.net/npm/toastify-js https://unpkg.com/@popperjs/core@2 https://unpkg.com/tippy.js@6 https://api.mapbox.com"
1212
object-src: "'none'"
13-
style-src: "'self' 'unsafe-inline' fonts.googleapis.com cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css https://fonts.gstatic.com"
13+
style-src: "'self' 'unsafe-inline' fonts.googleapis.com cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css https://fonts.gstatic.com https://api.mapbox.com"
1414
img-src: "'self' unocha.org hpc.tools content.hpc.tools fts.unocha.org data: api.mapbox.com browser-update.org https://fonts.gstatic.com"
1515
media-src: ''
1616
frame-src: "'self' https://content.hpc.tools https://www.youtube.com https://data.humdata.org https://datawrapper.dwcdn.net"
@@ -22,11 +22,11 @@ seckit_xss:
2222
upgrade-req: false
2323
policy-uri: ''
2424
x_xss:
25+
select: 0
2526
seckit_x_xss_option_disable: Disabled
2627
seckit_x_xss_option_0: '0'
2728
seckit_x_xss_option_1: 1;
2829
seckit_x_xss_option_1_block: '1; mode=block'
29-
select: 0
3030
seckit_csrf:
3131
origin: false
3232
origin_whitelist: ''

html/modules/custom/ghi_base_objects/assets/geojson/UN_Geodata_simplified.geojson

+1
Large diffs are not rendered by default.

html/modules/custom/ghi_base_objects/assets/geojson/countries.geojson

+261
Large diffs are not rendered by default.

html/modules/custom/ghi_base_objects/src/ApiObjects/Location.php

+115-6
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,42 @@
77
*/
88
class Location extends BaseObject {
99

10+
/**
11+
* Define the paths to the fallback files for geojson country data.
12+
*
13+
* The paths are relative to the module directory.
14+
*
15+
* The UN dataset which unfortunately has quite some issues and renders a lot
16+
* of artefacts. It comes from:
17+
* https://geoportal.un.org/arcgis/apps/sites/#/geohub/datasets/d7caaff3ef4b4f7c82689b7c4694ad92/about.
18+
*/
19+
const GEOJSON_FALLBACK_FILE_UN = 'assets/geojson/UN_Geodata_simplified.geojson';
20+
21+
/**
22+
* An alternative source.
23+
*
24+
* This comes from
25+
* https://github.com/datasets/geo-countries via
26+
* https://datahub.io/core/geo-countries and
27+
* https://www.naturalearthdata.com/downloads/10m-cultural-vectors/.
28+
*/
29+
const GEOJSON_FALLBACK_FILE_OTHER = 'assets/geojson/countries.geojson';
30+
1031
/**
1132
* {@inheritdoc}
1233
*/
1334
protected function map() {
1435
$data = $this->getRawData();
1536
return (object) [
1637
'location_id' => $data->id,
17-
'location_name' => $data->name,
38+
'location_name' => $data->name ?: 'Admin area ' . $data->externalId,
1839
'admin_level' => $data->adminLevel,
1940
'pcode' => $data->pcode,
41+
'iso3' => $data->iso3,
2042
'latLng' => [(string) $data->latitude, (string) $data->longitude],
2143
'filepath' => !empty($data->filepath) ? $data->filepath : NULL,
2244
'parent_id' => $data->parentId,
45+
'children' => $data->children ?? [],
2346
];
2447
}
2548

@@ -34,8 +57,21 @@ protected function map() {
3457
*/
3558
public function getGeoJsonLocalFilePath($refresh = FALSE) {
3659
$geojson_service = self::getGeoJsonService();
37-
$uri = $geojson_service->getGeoJsonLocalFilePath($this->filepath, $refresh);
38-
return $uri ? \Drupal::service('file_url_generator')->generate($uri)->toString() : NULL;
60+
$file_url_generator = self::fileUrlGenerator();
61+
if ($this->filepath && $uri = $geojson_service->getGeoJsonLocalFilePath($this->filepath, $refresh)) {
62+
// If we have a filepath, let's point to it. This comes from the API and
63+
// we store local copies of it.
64+
return $uri ? $file_url_generator->generate($uri)->toString() : NULL;
65+
}
66+
// Otherwise let's see if we can get another type of local file that is
67+
// extracted from a static geojson source and fetched via
68+
// self::getGeoJsonFallback().
69+
$local_filename = $this->iso3 . '.json';
70+
if (!$geojson_service->localFileExists($local_filename)) {
71+
$this->getGeoJsonFallback();
72+
}
73+
$filepath = $geojson_service->getLocalFilePath($local_filename);
74+
return $filepath ? $file_url_generator->generate($filepath)->toString() : NULL;
3975
}
4076

4177
/**
@@ -44,12 +80,65 @@ public function getGeoJsonLocalFilePath($refresh = FALSE) {
4480
* @param bool $refresh
4581
* Whether to refresh stored data.
4682
*
47-
* @return object
48-
* The geo json data object.
83+
* @return object|false
84+
* The geo json data object or FALSE.
4985
*/
5086
public function getGeoJson($refresh = FALSE) {
5187
$geojson_service = self::getGeoJsonService();
52-
return $geojson_service->getGeoJson($this->filepath, $refresh);
88+
$geojson = $this->filepath ? $geojson_service->getGeoJson($this->filepath, $refresh) : FALSE;
89+
if (!$geojson) {
90+
$geojson = $this->getGeoJsonFallback();
91+
}
92+
return $geojson;
93+
}
94+
95+
/**
96+
* Use a fallback to retrieve geojson polygon data for a location.
97+
*
98+
* @return object|false
99+
* The geo json data object or FALSE.
100+
*/
101+
private function getGeoJsonFallback() {
102+
if ($this->admin_level > 0) {
103+
// The fallback is available only for admin level 0 locations.
104+
return FALSE;
105+
}
106+
$geojson_service = self::getGeoJsonService();
107+
$local_filename = $this->iso3 . '.json';
108+
if ($geojson_service->localFileExists($local_filename)) {
109+
return $geojson_service->getLocalFileContent($local_filename);
110+
}
111+
112+
$geojson_file = self::moduleHandler()->getModule('ghi_base_objects')->getPath() . '/' . self::GEOJSON_FALLBACK_FILE_OTHER;
113+
if (!file_exists($geojson_file)) {
114+
return FALSE;
115+
}
116+
// Extract the features for the current location based on the iso3 code.
117+
$content = json_decode(file_get_contents($geojson_file));
118+
$features = array_filter($content->features, function ($item) {
119+
return property_exists($item->properties, 'iso3cd') && $item->properties->iso3cd == $this->iso3 || property_exists($item->properties, 'ISO_A3') && $item->properties->ISO_A3 == $this->iso3;
120+
});
121+
if (empty($features)) {
122+
return FALSE;
123+
}
124+
$features = array_values(array_map(function ($feature) {
125+
unset($feature->properties);
126+
return $feature;
127+
}, $features));
128+
$geojson = (object) [
129+
'type' => 'Feature',
130+
'geometry' => (object) [
131+
'type' => 'GeometryCollection',
132+
'geometries' => array_map(function ($feature) {
133+
return $feature->geometry;
134+
}, $features),
135+
],
136+
'properties' => (object) [
137+
'location_id' => $this->id(),
138+
],
139+
];
140+
$geojson_service->writeGeoJsonFile($local_filename, json_encode($geojson));
141+
return $geojson;
53142
}
54143

55144
/**
@@ -71,4 +160,24 @@ public static function getGeoJsonService() {
71160
return \Drupal::service('hpc_api.geojson');
72161
}
73162

163+
/**
164+
* Get the file url generator service.
165+
*
166+
* @return \Drupal\Core\File\FileUrlGeneratorInterface
167+
* The file url generator service.
168+
*/
169+
public static function fileUrlGenerator() {
170+
return \Drupal::service('file_url_generator');
171+
}
172+
173+
/**
174+
* Get the module handler service.
175+
*
176+
* @return \Drupal\Core\Extension\ModuleHandlerInterface
177+
* The module handler service.
178+
*/
179+
public static function moduleHandler() {
180+
return \Drupal::service('module_handler');
181+
}
182+
74183
}

html/modules/custom/ghi_base_objects/src/Plugin/EndpointQuery/LocationsQuery.php

+8-6
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,22 @@ class LocationsQuery extends EndpointQueryBase {
3737
* @param bool $include_expired
3838
* Include expired locations.
3939
*
40-
* @return object
41-
* An unprocessed response object from the API.
40+
* @return \Drupal\ghi_base_objects\ApiObjects\Location|null
41+
* A location.
4242
*/
43-
private function getCountryLocationData($country_id, $max_level = NULL, $include_expired = TRUE) {
43+
public function getCountryLocationData($country_id, $max_level = NULL, $include_expired = TRUE) {
4444
$this->setPlaceholder('country_id', $country_id);
4545
$this->endpointQuery->setEndpointArguments(array_filter([
4646
'maxLevel' => $max_level ?? self::MAX_LEVEL,
4747
'includeExpired' => $include_expired ? 'true' : NULL,
48-
]));
48+
], function ($item) {
49+
return $item !== NULL;
50+
}));
4951
$data = $this->getData();
5052
if (empty($data)) {
5153
return NULL;
5254
}
53-
return $data ?? NULL;
55+
return $data ? new Location($data) : NULL;
5456
}
5557

5658
/**
@@ -75,7 +77,7 @@ public function getCountryLocations($country, $max_level = self::MAX_LEVEL) {
7577
}
7678

7779
$data = $this->getCountryLocationData($country->id, $max_level);
78-
if (empty($data) || empty($data->children) || !is_array($data->children)) {
80+
if (!$data || empty($data->children) || !is_array($data->children)) {
7981
$this->setCache($cache_key, []);
8082
return [];
8183
}

html/modules/custom/ghi_blocks/ghi_blocks.libraries.yml

+100-19
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,98 @@ leaflet.sidebar:
7676
component:
7777
/libraries/leaflet-sidebar/src/L.Control.Sidebar.css: {}
7878

79-
map.base:
79+
mapbox_gl:
80+
version: 3.8.0
8081
js:
81-
js/map/map.search_control.js: {}
82+
https://api.mapbox.com/mapbox-gl-js/v3.8.0/mapbox-gl.js: {}
83+
css:
84+
component:
85+
https://api.mapbox.com/mapbox-gl-js/v3.8.0/mapbox-gl.css: {}
86+
87+
map.gl.sidebar:
88+
js:
89+
js/map.gl/map.sidebar.js: {}
90+
dependencies:
91+
- core/jquery
92+
- core/once
93+
- ghi_blocks/theme
94+
95+
map.gl.interactive_legend:
96+
js:
97+
js/map.gl/map.interactive_legend.js: {}
98+
dependencies:
99+
- core/jquery
100+
101+
map.gl.control.admin_level:
102+
js:
103+
js/map.gl/controls/map.control.admin_level.js: {}
104+
dependencies:
105+
- core/jquery
106+
107+
map.gl.control.disclaimer:
108+
js:
109+
js/map.gl/controls/map.control.disclaimer.js: {}
110+
111+
map.gl.control.search:
112+
js:
113+
js/map.gl/controls/map.control.search.js: {}
114+
dependencies:
115+
- core/jquery
116+
117+
map.gl.state:
118+
js:
119+
js/map.gl/map.state.js: {}
120+
dependencies:
121+
- core/jquery
122+
123+
map.gl:
124+
js:
125+
js/map.gl/map.mapbox.js: {}
126+
js/map.gl/styles/map.circle.js: {}
127+
js/map.gl/styles/map.chloropleth.js: {}
128+
js/map.gl/map.js: {}
129+
dependencies:
130+
- core/jquery
131+
- ghi_blocks/mapbox_gl
132+
- ghi_blocks/map.gl.state
133+
- ghi_blocks/map.gl.sidebar
134+
- ghi_blocks/map.gl.interactive_legend
135+
- ghi_blocks/map.gl.control.admin_level
136+
- ghi_blocks/map.gl.control.disclaimer
137+
- ghi_blocks/map.gl.control.search
138+
- ghi_blocks/map.leaflet.base
139+
140+
141+
142+
map.gl.plan_overview:
143+
js:
144+
js/map.gl/map.plan_overview.js: {}
145+
dependencies:
146+
- ghi_blocks/map.gl
147+
148+
map.gl.plan:
149+
js:
150+
js/map.gl/map.plan_attachment.js: {}
151+
dependencies:
152+
- ghi_blocks/map.gl
153+
154+
map.gl.operational_presence:
155+
js:
156+
js/map.gl/map.plan_operational_presence.js: {}
157+
dependencies:
158+
- ghi_blocks/map.gl
159+
160+
map.leaflet:
161+
js:
162+
js/map.leaflet/map.circle.js: {}
163+
js/map.leaflet/map.donut.js: {}
164+
js/map.leaflet/map.js: {}
165+
dependencies:
166+
- ghi_blocks/map.leaflet.base
167+
168+
map.leaflet.base:
169+
js:
170+
js/map.leaflet/map.search_control.js: {}
82171
dependencies:
83172
- hpc_common/tooltip
84173
- hpc_common/d3
@@ -89,31 +178,23 @@ map.base:
89178
- ghi_blocks/leaflet.search
90179
- ghi_blocks/leaflet.sidebar
91180

92-
map:
93-
js:
94-
js/map/map.circle.js: {}
95-
js/map/map.donut.js: {}
96-
js/map/map.js: {}
97-
dependencies:
98-
- ghi_blocks/map.base
99-
100-
map.plan:
181+
map.leaflet.plan:
101182
js:
102-
js/map/map.plan.js: {}
183+
js/map.leaflet/map.plan.js: {}
103184
dependencies:
104-
- ghi_blocks/map
185+
- ghi_blocks/map.leaflet
105186

106-
map.plan_overview:
187+
map.leaflet.plan_overview:
107188
js:
108-
js/map/map.plan_overview.js: {}
189+
js/map.leaflet/map.plan_overview.js: {}
109190
dependencies:
110-
- ghi_blocks/map
191+
- ghi_blocks/map.leaflet
111192

112-
map.chloropleth:
193+
map.leaflet.chloropleth:
113194
js:
114-
js/map/map.chloropleth.js: {}
195+
js/map.leaflet/map.chloropleth.js: {}
115196
dependencies:
116-
- ghi_blocks/map.base
197+
- ghi_blocks/map.leaflet.base
117198

118199
modal:
119200
js:

html/modules/custom/ghi_blocks/ghi_blocks.theme.inc

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use Drupal\Component\Utility\Html;
99
use Drupal\Component\Utility\Unicode;
1010
use Drupal\Core\Link;
1111
use Drupal\Core\Render\Markup;
12+
use Drupal\Core\StringTranslation\ByteSizeMarkup;
1213
use Drupal\Core\Url;
1314
use Drupal\ghi_blocks\Plugin\ConfigurationContainerItem\DocumentLink;
1415
use Drupal\ghi_plans\Entity\Plan;
@@ -178,7 +179,7 @@ function ghi_blocks_build_document_download_link(array $document, $language = NU
178179
// Get the filesize.
179180
$filesize = NULL;
180181
if (!empty($document['filesize'])) {
181-
$filesize = format_size($document['filesize']);
182+
$filesize = ByteSizeMarkup::create($document['filesize']);
182183
}
183184

184185
// Link title.

0 commit comments

Comments
 (0)