diff --git a/config.js b/config.js
index e08a445..947e548 100644
--- a/config.js
+++ b/config.js
@@ -2,11 +2,12 @@ const one_day = 1440;
module.exports = {
title: "ukraine",
display_title: "Civilian Harm in Ukraine",
- SERVER_ROOT: 'https://ukraine.bellingcat.com/ukraine-server',
+ SERVER_ROOT: "https://ukraine.bellingcat.com/ukraine-server",
EVENTS_EXT: "/api/ukraine/export_events/deeprows",
SOURCES_EXT: "/api/ukraine/export_sources/deepids",
ASSOCIATIONS_EXT: "/api/ukraine/export_associations/deeprows",
- MAPBOX_TOKEN: "pk.eyJ1IjoiYmVsbGluZ2NhdC1tYXBib3giLCJhIjoiY2tleW0wbWliMDA1cTJ5bzdkbTRraHgwZSJ9.GJQkjPzj8554VhR5SPsfJg",
+ MAPBOX_TOKEN:
+ "pk.eyJ1IjoiYmVsbGluZ2NhdC1tYXBib3giLCJhIjoiY2tleW0wbWliMDA1cTJ5bzdkbTRraHgwZSJ9.GJQkjPzj8554VhR5SPsfJg",
// MEDIA_EXT: "/api/media",
DATE_FMT: "MM/DD/YYYY",
TIME_FMT: "HH:mm",
@@ -16,7 +17,7 @@ module.exports = {
debug: true,
map: {
// anchor: [49.02421913, 31.43836003],
- anchor: [48.3326259, 33.199514470],
+ anchor: [48.3326259, 33.19951447],
maxZoom: 18,
minZoom: 4,
startZoom: 6,
@@ -24,7 +25,7 @@ module.exports = {
},
cluster: { radius: 50, minZoom: 5, maxZoom: 12 },
associations: {
- defaultCategory: "Weapon System"
+ defaultCategory: "Weapon System",
},
timeline: {
dimensions: {
@@ -32,15 +33,12 @@ module.exports = {
contentHeight: 150,
},
zoomLevels: [
- { label: 'Zoom to 1 week', duration: 7 * one_day },
- { label: 'Zoom to 2 weeks', duration: 14 * one_day },
- { label: 'Zoom to 1 month', duration: 31 * one_day },
- { label: 'Zoom to 3 months', duration: 3 * 31 * one_day },
- ],
- range: [
- new Date(Date.now() - (14 * (60 * 60 * 1000 * 24))),
- new Date()
+ { label: "Zoom to 1 week", duration: 7 * one_day },
+ { label: "Zoom to 2 weeks", duration: 14 * one_day },
+ { label: "Zoom to 1 month", duration: 31 * one_day },
+ { label: "Zoom to 3 months", duration: 3 * 31 * one_day },
],
+ range: [new Date(Date.now() - 14 * (60 * 60 * 1000 * 24)), new Date()],
// rangeLimits: []
},
intro: [
@@ -71,8 +69,8 @@ module.exports = {
"## A Note on Bellingcat's Global Authentication Project",
"The Global Authentication Project consists of a wide community of open source researchers assisting in Bellingcat research through structured tasks and feedback. Our aim is to authenticate events taking place around the world and fill in the gaps of knowledge that exist, particularly in situations where there are vast quantities of data. In creating a community for those interested in open source research, we are fostering Bellingcat's original aim of solving problems **together**, to diversify our investigations and promote the use of these skills. For this dataset, we are working with many individuals who have Ukrainian language skills and others with local contextual knowledge of the events and places seen on the map. Other participants include individuals skilled in geolocation and chronolocation, with all contributions being vetted by Bellingcat researchers. As we expand the Global Authentication Project in the coming months, more information will be available on our website and Twitter.",
"## Feedback",
- "This map will continue to change and be updated for the duration of this conflict. We welcome feedback on our methodology, data collection and take transparency seriously. Should you have any direct feedback about the platform, please indicate it on this [form](https://forms.gle/cV2YAojBoh6h4T3XA)."
- ]
+ "This map will continue to change and be updated for the duration of this conflict. We welcome feedback on our methodology, data collection and take transparency seriously. Should you have any direct feedback about the platform, please indicate it on this [form](https://forms.gle/cV2YAojBoh6h4T3XA).",
+ ],
},
toolbar: {
panels: {
@@ -87,30 +85,43 @@ module.exports = {
// label: "Unverified",
// description: "todo",
// }
- }
- }
+ },
+ },
},
- spotlights: {}
+ spotlights: {},
},
ui: {
coloring: {
mode: "STATIC",
maxNumOfColors: 9,
defaultColor: "#dfdfdf",
- colors: ["#7E57C2", "#F57C00", "#FFEB3B", "#D34F73", "#08B2E3", "#A1887F", "#90A4AE", "#E57373", "#80CBC4"],
+ colors: [
+ "#7E57C2",
+ "#F57C00",
+ "#FFEB3B",
+ "#D34F73",
+ "#08B2E3",
+ "#A1887F",
+ "#90A4AE",
+ "#E57373",
+ "#80CBC4",
+ ],
},
card: {
layout: {
- template: "sourced"
- }
+ template: "sourced",
+ },
},
carto: {
- eventRadius: 8
+ eventRadius: 8,
},
timeline: {
- eventRadius: 9
+ eventRadius: 9,
+ },
+ tiles: {
+ current: "bellingcat-mapbox/cl0qnou2y003m15s8ieuyhgsy",
+ default: "bellingcat-mapbox/cl0qnou2y003m15s8ieuyhgsy",
},
- tiles: 'bellingcat-mapbox/cl0qnou2y003m15s8ieuyhgsy'
},
features: {
USE_CATEGORIES: false,
@@ -123,6 +134,7 @@ module.exports = {
USE_SHAPES: false,
USE_COVER: true,
USE_INTRO: false,
+ USE_SATELLITE_OVERLAY_TOGGLE: true,
USE_SEARCH: false,
USE_SITES: false,
ZOOM_TO_TIMEFRAME_ON_TIMELINE_CLICK: one_day,
@@ -130,7 +142,7 @@ module.exports = {
USE_MEDIA_CACHE: false,
GRAPH_NONLOCATED: false,
NARRATIVE_STEP_STYLES: false,
- CUSTOM_EVENT_FIELDS: []
+ CUSTOM_EVENT_FIELDS: [],
},
},
-};
\ No newline at end of file
+};
diff --git a/src/actions/index.js b/src/actions/index.js
index 0035777..266310c 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -400,3 +400,17 @@ export function fetchSourceError(msg) {
msg,
};
}
+
+export const USE_SATELLITE_TILES_OVERLAY = "USE_SATELLITE_TILES_OVERLAY";
+export function useSatelliteTilesOverlay() {
+ return {
+ type: USE_SATELLITE_TILES_OVERLAY,
+ };
+}
+
+export const RESET_TILES_OVERLAY = "RESET_TILES_OVERLAY";
+export function resetTilesOverlay() {
+ return {
+ type: RESET_TILES_OVERLAY,
+ };
+}
diff --git a/src/common/data/copy.json b/src/common/data/copy.json
index e2ba701..8cb59c6 100644
--- a/src/common/data/copy.json
+++ b/src/common/data/copy.json
@@ -1,5 +1,9 @@
{
"es-MX": {
+ "tiles": {
+ "default": "Predeterminado",
+ "satellite": "Satélite"
+ },
"loading": "Cargando...",
"legend": {
"view2d": {
@@ -90,6 +94,10 @@
}
},
"en-US": {
+ "tiles": {
+ "default": "Default",
+ "satellite": "Satellite"
+ },
"loading": "Loading...",
"legend": {
"view2d": {
diff --git a/src/components/space/carto/Map.js b/src/components/space/carto/Map.js
index d2bb2f6..eaf6a9c 100644
--- a/src/components/space/carto/Map.js
+++ b/src/components/space/carto/Map.js
@@ -1,4 +1,5 @@
/* global L */
+import { bindActionCreators } from "redux";
import "leaflet";
import React from "react";
import { Portal } from "react-portal";
@@ -6,6 +7,7 @@ import Supercluster from "supercluster";
import { isMobileOnly } from "react-device-detect";
import { connect } from "react-redux";
+import * as actions from "../../../actions";
import * as selectors from "../../../selectors";
import Sites from "./atoms/Sites";
@@ -15,6 +17,7 @@ import Clusters from "./atoms/Clusters";
import SelectedEvents from "./atoms/SelectedEvents";
import Narratives from "./atoms/Narratives";
import DefsMarkers from "./atoms/DefsMarkers";
+import SatelliteOverlayToggle from "./atoms/SatelliteOverlayToggle";
import LoadingOverlay from "../../atoms/Loading";
import {
@@ -41,6 +44,7 @@ class Map extends React.Component {
this.svgRef = React.createRef();
this.map = null;
this.superclusterIndex = null;
+ this.tileLayer = null;
this.state = {
mapTransformX: 0,
mapTransformY: 0,
@@ -53,14 +57,22 @@ class Map extends React.Component {
componentDidMount() {
if (this.map === null) {
this.initializeMap();
+ this.initializeTileLayer();
}
window.dispatchEvent(new Event("resize"));
}
+ componentDidUpdate(prevProps) {
+ if (prevProps.ui.tiles !== this.props.ui.tiles && this.map) {
+ this.initializeTileLayer();
+ }
+ }
+
componentWillReceiveProps(nextProps) {
if (!isIdentical(nextProps.domain.locations, this.props.domain.locations)) {
this.loadClusterData(nextProps.domain.locations);
}
+
// Set appropriate zoom for narrative
const { bounds } = nextProps.app.map;
if (!isIdentical(bounds, this.props.app.map.bounds) && bounds !== null) {
@@ -92,6 +104,36 @@ class Map extends React.Component {
}
}
+ initializeTileLayer() {
+ if (!this.map) {
+ return;
+ }
+
+ if (
+ supportedMapboxMap.indexOf(this.props.ui.tiles) !== -1 &&
+ process.env.MAPBOX_TOKEN &&
+ process.env.MAPBOX_TOKEN !== defaultToken
+ ) {
+ this.tileLayer = L.tileLayer(
+ `http://a.tiles.mapbox.com/v4/mapbox.${this.props.ui.tiles}/{z}/{x}/{y}@2x.png?access_token=${process.env.MAPBOX_TOKEN}`
+ );
+ } else if (
+ process.env.MAPBOX_TOKEN &&
+ process.env.MAPBOX_TOKEN !== defaultToken
+ ) {
+ this.tileLayer = L.tileLayer(
+ `https://api.mapbox.com/styles/v1/${this.props.ui.tiles}/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_TOKEN}`
+ // `http://a.tiles.mapbox.com/styles/v1/${this.props.ui.tiles}/tiles/{z}/{x}/{y}?access_token=${process.env.MAPBOX_TOKEN}`
+ );
+ } else {
+ this.tileLayer = L.tileLayer(
+ "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
+ // "https://api.maptiler.com/maps/bright/256/{z}/{x}/{y}.png?key="
+ );
+ }
+ this.tileLayer.addTo(this.map);
+ }
+
initializeMap() {
/**
* Creates a Leaflet map and a tilelayer for the map background
@@ -111,31 +153,7 @@ class Map extends React.Component {
// Initialize supercluster index
this.superclusterIndex = new Supercluster(clusterConfig);
- let firstLayer;
-
- if (
- supportedMapboxMap.indexOf(this.props.ui.tiles) !== -1 &&
- process.env.MAPBOX_TOKEN &&
- process.env.MAPBOX_TOKEN !== defaultToken
- ) {
- firstLayer = L.tileLayer(
- `http://a.tiles.mapbox.com/v4/mapbox.${this.props.ui.tiles}/{z}/{x}/{y}@2x.png?access_token=${process.env.MAPBOX_TOKEN}`
- );
- } else if (
- process.env.MAPBOX_TOKEN &&
- process.env.MAPBOX_TOKEN !== defaultToken
- ) {
- firstLayer = L.tileLayer(
- `https://api.mapbox.com/styles/v1/${this.props.ui.tiles}/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_TOKEN}`
- // `http://a.tiles.mapbox.com/styles/v1/${this.props.ui.tiles}/tiles/{z}/{x}/{y}?access_token=${process.env.MAPBOX_TOKEN}`
- );
- } else {
- firstLayer = L.tileLayer(
- "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
- // "https://api.maptiler.com/maps/bright/256/{z}/{x}/{y}.png?key="
- );
- }
- firstLayer.addTo(map);
+ this.initializeTileLayer(map);
map.keyboard.disable();
map.zoomControl.remove();
@@ -517,6 +535,13 @@ class Map extends React.Component {
ui={isFetchingDomain}
language={this.props.app.language}
/>
+ {this.props.features.USE_SATELLITE_OVERLAY_TOGGLE && (
+