Skip to content

Commit

Permalink
Merge pull request #122 from NASA-IMPACT/develop
Browse files Browse the repository at this point in the history
Release 0.4.0
  • Loading branch information
olafveerman authored Jun 5, 2020
2 parents 621bf2d + f9d1bd0 commit de8b1bd
Show file tree
Hide file tree
Showing 60 changed files with 1,912 additions and 933 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/graphics/content/hubei_vir_after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/graphics/content/hubei_vir_before.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/graphics/content/no2_south_america.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/graphics/content/wuhan_bef_after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 43 additions & 21 deletions app/assets/scripts/components/about/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ import {
InpageTitle,
InpageBody
} from '../../styles/inpage';
import Constrainer from '../../styles/constrainer';
import Prose from '../../styles/type/prose';

import {
Fold,
FoldTitle
} from '../../styles/fold';
import { glsp } from '../../styles/utils/theme-values';

import Constrainer from '../../styles/constrainer';
const PageConstrainer = styled(Constrainer)`
padding-top: ${glsp(4)};
padding-bottom: ${glsp(4)};
import Prose from '../../styles/type/prose';
${Prose} {
max-width: 50rem;
}
const AboutProse = styled(Prose)`
grid-row: 1;
grid-column: span 8;
> *:not(:last-child) {
margin-bottom: ${glsp(2)};
}
`;

export default class About extends React.Component {
Expand All @@ -38,18 +41,37 @@ export default class About extends React.Component {
</InpageHeaderInner>
</InpageHeader>
<InpageBody>
<Fold>
<Constrainer>
<AboutProse>
<FoldTitle>The tool</FoldTitle>
<p>
The COVID EO dashbord provides streaming data about the
pandemic to inform decisionmakers in government, community
leaders, health responders, and the business community.
</p>
</AboutProse>
</Constrainer>
</Fold>
<PageConstrainer>
<Prose>
<p>
As the world moved indoors to shelter from the global pandemic sparked by the novel coronavirus, we
could perceive changes on our planet. The sky seemed a little bluer, the air a little fresher, the animals in
our yards more abundant.
</p>
<p>
NASA’s continuous and sometimes near-real-time measurements of Earth allow for understanding both the systems
changes themselves and the potential impact on economies and society during the pandemic – and as the world
slowly returns to operations.
</p>
<p>
This dashboard features data collected and analyzed by the National Aeronautics and Space Administration (NASA).
Information about Earth systems is gathered by a fleet of powerful global Earth-Observing satellites, instruments
aboard the International Space Station, from airborne science campaigns, and via ground observations. With this
data we have been able to monitor some of those changes andand this is allowing us to track and compare these
changes over time.
</p>
<p>
NASA will further expand the impact of the data sets presented in this dashboard in collaboration with
European Space Agency (ESA) and the Japan Aerospace Exploration Agency (JAXA), who also have created their own
online data portals to provide an even richer picture of what is happening on our home planet during this time of
world crisis by developing a fourth dashboard that will combine the unique data of each agency for more comparisons
and deeper understandings now and over time.
</p>
<p>
To learn more about NASA Earth Science, go to <a href='https://nasa.gov/earth'>nasa.gov/earth</a>.
</p>
</Prose>
</PageConstrainer>
</InpageBody>
</Inpage>
</App>
Expand Down
2 changes: 1 addition & 1 deletion app/assets/scripts/components/common/accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ function AccordionFoldCmp ({
);
}
AccordionFoldCmp.propTypes = {
as: T.node,
as: T.any,
id: T.string,
className: T.string,
isFoldExpanded: T.bool,
Expand Down
17 changes: 15 additions & 2 deletions app/assets/scripts/components/common/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import T from 'prop-types';
import { withRouter } from 'react-router';
import styled from 'styled-components';

import MetaTags from './meta-tags';
Expand Down Expand Up @@ -38,6 +39,17 @@ class App extends Component {
this.resizeListener = this.resizeListener.bind(this);
}

componentDidMount () {
window.scrollTo(0, 0);
}

// Handle cases where the page is updated without changing
componentDidUpdate (prevProps) {
if (this.props.location && this.props.location.pathname !== prevProps.location.pathname) {
window.scrollTo(0, 0);
}
}

resizeListener ({ width }) {
this.setState({
useShortTitle: width < mediaRanges.small[0]
Expand All @@ -63,7 +75,8 @@ class App extends Component {

App.propTypes = {
pageTitle: T.string,
children: T.node
children: T.node,
location: T.object
};

export default App;
export default withRouter(App);
37 changes: 21 additions & 16 deletions app/assets/scripts/components/common/data-browser/bisector.layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,26 @@ import {
} from 'date-fns';

import { themeVal } from '../../../styles/utils/general';
import { utcDate, bisectByDate } from '../../../utils/utils';

const roundDate = (date, interval) => {
if (interval === 'day') {
const h = getHours(date);
return h >= 12
? startOfDay(add(date, { days: 1 }))
: startOfDay(date);
const getClosestDate = (data, date, timeUnit) => {
// If we're working with a discrete domain, get the closest value.
if (data.length > 2) {
return bisectByDate(data, date, d => utcDate(d));
} else {
const days = getDaysInMonth(date);
const d = getDate(date);
return d >= days / 2
? startOfMonth(add(date, { months: 1 }))
: startOfMonth(date);
// If we only have start and end, round based on time unit.
if (timeUnit === 'day') {
const h = getHours(date);
return h >= 12
? startOfDay(add(date, { days: 1 }))
: startOfDay(date);
} else {
const days = getDaysInMonth(date);
const d = getDate(date);
return d >= days / 2
? startOfMonth(add(date, { months: 1 }))
: startOfMonth(date);
}
}
};

Expand All @@ -48,8 +55,6 @@ const styles = props => css`
export default {
styles,
init: ctx => {
const { timeUnit } = ctx.props;

const bisectorG = ctx.dataCanvas
.append('g')
.attr('class', 'bisector');
Expand All @@ -67,7 +72,7 @@ export default {
.style('pointer-events', 'all')
.on('mouseover', function () {
const xPos = d3.mouse(this)[0];
const date = roundDate(ctx.xScale.invert(xPos), timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
const xPosSnap = ctx.xScale(date);
bisectorG.select('.bisector-interact').style('display', '');
ctx.onInternalAction('bisector.show', { date, x: xPosSnap });
Expand All @@ -78,7 +83,7 @@ export default {
})
.on('mousemove', function () {
const xPos = d3.mouse(this)[0];
const date = roundDate(ctx.xScale.invert(xPos), timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
const xPosSnap = ctx.xScale(date);
const { height } = ctx.getSize();
bisectorG.select('.bisector-interact')
Expand All @@ -90,7 +95,7 @@ export default {
})
.on('click', function () {
const xPos = d3.mouse(this)[0];
const date = roundDate(ctx.xScale.invert(xPos), timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
ctx.props.onAction('date.set', { date });
});
},
Expand Down
9 changes: 7 additions & 2 deletions app/assets/scripts/components/common/data-browser/chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const formatDate = (date, interval) => {
if (interval === 'day') {
return format(date, 'dd MMMM yyyy');
} else {
return format(date, "MMMM yy''");
return format(date, 'MMMM yyyy');
}
};

Expand Down Expand Up @@ -165,9 +165,14 @@ class DataBrowserChart extends React.Component {

// ---------------------------------------------------
// Functions
const xDomain = [
props.xDomain[0],
props.xDomain[props.xDomain.length - 1]
];

this.xScale = d3
.scaleTime()
.domain(props.xDomain)
.domain(xDomain)
.range([0, width]);

// this.yScale = d3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const styles = props => css`
stroke: ${props.swatch};
stroke-linecap: round;
}
.point {
fill: ${props.swatch};
}
}
`;

Expand All @@ -21,27 +24,54 @@ export default {
},

update: ctx => {
const { dataCanvas, xScale } = ctx;
const { dataCanvas, xScale, props } = ctx;
const { height } = ctx.getSize();
// Limit data to existing date domain.
const dateDomain = xScale.domain();

const dataSeries = dataCanvas.select('.data-extent');

const lines = dataSeries.selectAll('.line').data([dateDomain]);

// Remove old.
lines.exit().remove();
// Handle new.
lines
.enter()
.append('line')
.attr('class', 'line')
.attr('fill', 'none')
.merge(lines)
// Update current.
.attr('x1', d => xScale(utcDate(d[0])))
.attr('y1', height - 8)
.attr('x2', d => xScale(utcDate(d[1])))
.attr('y2', height - 8);
const isDiscrete = props.xDomain.length > 2;

// When we have more than 2 date points, we are showing the individual dates
// that are available.
// These are represented as circles. Continuous data is represented as
// a line.
if (isDiscrete) {
dataSeries.selectAll('.line').style('display', 'none');
const points = dataSeries.selectAll('.point').data(props.xDomain);

// Remove old.
points.exit().remove();
// Handle new.
points
.enter()
.append('circle')
.attr('r', 4)
.attr('class', 'point')
.merge(points)
// Update current.
.style('display', '')
.attr('cx', d => xScale(utcDate(d)))
.attr('cy', d => height - 8);
} else {
dataSeries.selectAll('.poin').style('display', 'none');
const dateDomain = xScale.domain();
const lines = dataSeries.selectAll('.line').data([dateDomain]);

// Remove old.
lines.exit().remove();
// Handle new.
lines
.enter()
.append('line')
.attr('class', 'line')
.attr('fill', 'none')
.merge(lines)
// Update current.
.style('display', '')
.attr('x1', d => xScale(utcDate(d[0])))
.attr('y1', height - 8)
.attr('x2', d => xScale(utcDate(d[1])))
.attr('y2', height - 8);
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
const { height } = ctx.getSize();

const xAxis = d3fc.axisBottom(xScale)
.tickFormat(d3.timeFormat('%b %y\''));
.tickFormat(d3.timeFormat('%b \'%y'));

svg.select('.x.axis')
.attr('transform', `translate(${left},${height + top + 8})`)
Expand Down
6 changes: 4 additions & 2 deletions app/assets/scripts/components/common/layers/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import no2 from './layer-no2';
import population from './layer-population';
import carCount from './layer-car-count';
import nightlights from './layer-nightlights';
import nightlightsViirs from './layer-nightlights-viirs';
import nightlightsHd from './layer-nightlights-hd';

export default [
no2,
population,
carCount,
nightlights
nightlightsViirs,
nightlightsHd
];
16 changes: 9 additions & 7 deletions app/assets/scripts/components/common/layers/layer-car-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import config from '../../../config';
export default {
id: 'car-count',
name: 'Car count',
type: 'raster',
type: 'raster-timeseries',
domain: ['2019-12-10', '2020-01-05', '2020-01-12', '2020-01-19', '2020-01-24', '2020-01-29', '2020-02-05', '2020-02-10', '2020-02-17', '2020-02-18', '2020-02-22', '2020-03-05', '2020-03-12', '2020-03-17', '2020-03-24', '2020-03-29', '2020-03-31', '2020-04-05', '2020-04-17', '2020-04-28', '2020-04-29', '2020-05-07'],
timeUnit: 'day',
source: {
type: 'raster',
tiles: [
`${config.api}/{z}/{x}/{y}@1x?url=s3://covid-eo-data/ALOS_SAMPLE/alos2-s1-beijing_2019_12_10.tif&resampling_method=nearest&bidx=1&rescale=0%2C65536`
`${config.api}/{z}/{x}/{y}@1x?url=s3://covid-eo-data/ALOS_SAMPLE/alos2-s1-beijing_{date}.tif&resampling_method=nearest&bidx=1&rescale=1%2C65536`
]
},
exclusiveWith: ['no2'],
// swatch: {
// color: '#F55E2C',
// name: 'Orange'
// },
exclusiveWith: ['no2', 'gibs-population', 'nightlights-viirs', 'nightlights-hd'],
swatch: {
color: '#666666',
name: 'Grey'
},
legend: {
type: 'gradient',
min: 'less',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import config from '../../../config';

export default {
id: 'nightlights-hd',
name: 'Nightlights HD',
type: 'raster-timeseries',
timeUnit: 'month',
domain: [
'2020-01-01',
'2020-05-01'
],
source: {
type: 'raster',
tiles: [
`${config.api}/{z}/{x}/{y}@1x?url=s3://covid-eo-data/BMHD_30M_MONTHLY/BMHD_VNP46A2_{spotlightId}_{date}_cog.tif&resampling_method=bilinear&bidx=1%2C2%2C3`
]
},
exclusiveWith: ['no2', 'gibs-population', 'car-count', 'nightlights-viirs'],
swatch: {
color: '#f2a73a',
name: 'Gold'
},
legend: {
type: 'gradient',
min: 'less',
max: 'more',
stops: [
'#08041d',
'#1f0a46',
'#52076c',
'#f57c16',
'#f7cf39'
]
},
info: null
};
Loading

0 comments on commit de8b1bd

Please sign in to comment.