Commit 512b0794 authored by Matija Obreza's avatar Matija Obreza

Merge branch '202-mappage-center-zoom-level-in-url' into 'master'

MapPage center+zoom level in URL

Closes #202

See merge request genesys-pgr/genesys-ui!204
parents 161ae8ad 1fbae9b8
......@@ -402,7 +402,12 @@
"MCPD": "MCPD",
"zip": "ZIP",
"climateAtCollection": "Climate at origin",
"additionalInfo": "Bioclimatic variables"
"additionalInfo": "Bioclimatic variables",
"climateSimilar": {
"title": "Accessions with similar climatic properties",
"intro": "Georeferenced accesions in Genesys are linked to their climate data based on worldclim.org datasets. Genesys will try to find similar georeferenced accessions that match the basic climatic parameters: annual mean temperature, seasonality and rainfall.",
"view": "List accessions"
}
},
"browse": {
"title": "Accession browser",
......@@ -410,7 +415,11 @@
},
"map": {
"andMore": "And {{otherMore}} more",
"kml": "KML"
"kml": "KML",
"filterAccessions": "Filter accessions",
"pick": "Show climate",
"stopPick": "Cancel",
"noClimateData": "No climate data available for selected location"
}
}
......
......@@ -15,6 +15,7 @@ import { RECEIVE_ACCESSIONS, RECEIVE_ACCESSION, RECEIVE_ACCESSION_OVERVIEW, APPE
import AccessionService from 'service/genesys/AccessionService';
import { showSnackbar } from 'actions/snackbar';
import Page from 'model/Page';
import TileClimate from 'model/genesys/TileClimate';
const receiveAccessions = (paged: FilteredPage<Accession>, error = null) => ({
type: RECEIVE_ACCESSIONS,
......@@ -52,12 +53,12 @@ export const updateRoute = (paged: FilteredPage<Accession>, path: string = '/a')
s: paged.sort[0].property === Accession.DEFAULT_SORT.property ? undefined : paged.sort[0].property,
d: paged.sort[0].direction === Accession.DEFAULT_SORT.direction ? undefined : paged.sort[0].direction,
};
dispatch(updateRoute2(paged.filterCode, path, qs));
dispatch(updateRouteWithFilterCode(paged.filterCode, path, qs));
};
export const updateRoute2 = (filterCode: string, path: string = '/a', qs?: any) => (dispatch) => {
export const updateRouteWithFilterCode = (filterCode: string, path: string = '/a', qs?: any, postfix: string = '') => (dispatch) => {
console.log(`Update route2 ${filterCode} ${path}`, qs);
dispatch(navigateTo(filterCode ? `${path}/${filterCode}` : path, qs));
dispatch(navigateTo(filterCode ? `${path}/${filterCode}${postfix}` : path, qs));
};
export const applyFilters = (filters: string | AccessionFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
......@@ -97,7 +98,7 @@ export const applyOverviewFilters = (filters: string | AccessionFilter, page: IP
return AccessionService.listOverview(filters)
.then((overview) => {
dispatch(receiveAccessionOverview(overview));
dispatch(updateRoute2(overview.filterCode, '/a/overview'));
dispatch(updateRouteWithFilterCode(overview.filterCode, '/a/overview'));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionOverview(null, error));
......@@ -114,7 +115,7 @@ export const loadAccessionsOverviewPage = (filterCode: string) => (dispatch) =>
});
};
export const loadAccessionsMapInfo = (filters: string | AccessionFilter) => (dispatch) => {
export const loadAccessionsMapInfo = (filters: string | AccessionFilter, viewPort?: {center: number[], zoom: number}) => (dispatch) => {
return AccessionService.mapInfo(filters)
.then((mapInfo: AccessionMapInfo) => {
if (!(mapInfo.bounds[0][0] && mapInfo.bounds[0][1] && mapInfo.bounds[1][0] && mapInfo.bounds[1][1])) {
......@@ -122,7 +123,12 @@ export const loadAccessionsMapInfo = (filters: string | AccessionFilter) => (dis
console.log('One of map bounds is null, setting to default.');
}
dispatch(receiveAccessionMapInfo(mapInfo));
dispatch(updateRoute2(mapInfo.filterCode, '/a/map'));
if (viewPort && viewPort.zoom && viewPort.center && viewPort.center.length === 2) {
console.log(`viewPort @..,z${viewPort.zoom}`, viewPort);
dispatch(updateRouteWithFilterCode(mapInfo.filterCode, '/a/map', null, viewPort && viewPort.center && `/@${viewPort.center[0]},${viewPort.center[1]},${viewPort.zoom}z`));
} else {
dispatch(updateRouteWithFilterCode(mapInfo.filterCode, '/a/map'));
}
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveAccessionMapInfo(null, error));
......@@ -207,6 +213,68 @@ const receiveTileLayerInfo = (tileLayer: MapLayer) => ({
payload: {tileLayer},
});
export const updateTileLayerInfo = (tileLayer: MapLayer) => (dispatch) => {
export const updateTileLayerInfo = (tileLayer: MapLayer) => (dispatch) => {
return dispatch(receiveTileLayerInfo(tileLayer));
};
const makeRange = (variable: number, diff: number) => {
return {
ge: Math.round(variable - diff),
le: Math.round(variable + diff),
};
};
export const applyClimateFilters = (climate: TileClimate, extraFilters?: any) => (dispatch) => {
// BIO1 = Annual Mean Temperature !!
// BIO2 = Mean Diurnal Range (Mean of monthly (max temp - min temp))
// BIO3 = Isothermality (BIO2/BIO7) (* 100)
// BIO4 = Temperature Seasonality (standard deviation *100)
// BIO5 = Max Temperature of Warmest Month
// BIO6 = Min Temperature of Coldest Month
// BIO7 = Temperature Annual Range (BIO5-BIO6)
// BIO8 = Mean Temperature of Wettest Quarter
// BIO9 = Mean Temperature of Driest Quarter
// BIO10 = Mean Temperature of Warmest Quarter
// BIO11 = Mean Temperature of Coldest Quarter
// BIO12 = Annual Precipitation
// BIO13 = Precipitation of Wettest Month
// BIO14 = Precipitation of Driest Month
// BIO15 = Precipitation Seasonality (Coefficient of Variation)
// BIO16 = Precipitation of Wettest Quarter
// BIO17 = Precipitation of Driest Quarter
// BIO18 = Precipitation of Warmest Quarter !!
// BIO19 = Precipitation of Coldest Quarter !!
const tempDiff = 2;
const filter = {
// taxa: {
// genus: [ accession.taxonomy.genus ],
// // species: [ accession.taxonomy.species ],
// },
geo: {
climate: {
// temperature
bio1: makeRange(climate.bio1, tempDiff),
// bio2: makeRange(climate.bio2, tempDiff),
bio4: makeRange(climate.bio4, climate.bio4 * .50),
// bio7: makeRange(climate.bio7, tempDiff),
// bio8: makeRange(climate.bio8, tempDiff),
// bio9: makeRange(climate.bio9, tempDiff),
// bio10: makeRange(climate.bio10, tempDiff),
// bio11: makeRange(climate.bio11, tempDiff),
// precipitation
bio12: makeRange(climate.bio12, climate.bio12 * .25),
// bio13: makeRange(climate.bio13, precDif),
// bio14: makeRange(climate.bio14, precDif),
// bio15: makeRange(climate.bio15, climate.bio15 * .25),
bio18: makeRange(climate.bio18, climate.bio18 * .25),
bio19: makeRange(climate.bio19, climate.bio19 * .25),
},
},
...extraFilters,
};
dispatch(applyFilters(filter));
};
......@@ -6,6 +6,7 @@ export const RECEIVE_ACCESSION_AUDIT_LOG = 'accessions/RECEIVE_ACCESSION_AUDIT_L
export const RECEIVE_ACCESSION = 'accessions/RECEIVE_ACCESSION';
export const RECEIVE_ACCESSION_MAPINFO = 'accessions/RECEIVE_ACCESSION_MAPINFO';
export const ACCESSION_FILTERFORM = 'Form/Accession/ACCESSION_FILTERFORM';
export const ACCESSION_MAP_FILTERFORM = 'Form/Accession/ACCESSION_MAP_FILTERFORM';
export const ACCESSION_FORM = 'Form/Accession/ACCESSION_FORM';
// Dashboard
......
......@@ -12,6 +12,16 @@ const publicRoutes = [
component: Loadable({ loader: () => import(/* webpackMode:"lazy", webpackChunkName: "accessions" */'accessions/ui/OverviewPage') }),
exact: true,
},
{
path: '/a/map/:filterCode(v.+)?/@:lat,:lng,:zoom?z',
component: Loadable({ loader: () => import(/* webpackMode:"lazy", webpackChunkName: "accessions" */'accessions/ui/MapPage') }),
exact: true,
},
{
path: '/a/map/@:lat,:lng,:zoom?z',
component: Loadable({ loader: () => import(/* webpackMode:"lazy", webpackChunkName: "accessions" */'accessions/ui/MapPage') }),
exact: true,
},
{
path: '/a/map/:filterCode(v.+)?',
component: Loadable({ loader: () => import(/* webpackMode:"lazy", webpackChunkName: "accessions" */'accessions/ui/MapPage') }),
......
......@@ -59,7 +59,12 @@
"MCPD": "MCPD",
"zip": "ZIP",
"climateAtCollection": "Climate at origin",
"additionalInfo": "Bioclimatic variables"
"additionalInfo": "Bioclimatic variables",
"climateSimilar": {
"title": "Accessions with similar climatic properties",
"intro": "Georeferenced accesions in Genesys are linked to their climate data based on worldclim.org datasets. Genesys will try to find similar georeferenced accessions that match the basic climatic parameters: annual mean temperature, seasonality and rainfall.",
"view": "List accessions"
}
},
"browse": {
"title": "Accession browser",
......@@ -67,7 +72,11 @@
},
"map": {
"andMore": "And {{otherMore}} more",
"kml": "KML"
"kml": "KML",
"filterAccessions": "Filter accessions",
"pick": "Show climate",
"stopPick": "Cancel",
"noClimateData": "No climate data available for selected location"
}
}
......
import * as React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { translate } from 'react-i18next';
import { withStyles } from '@material-ui/core/styles';
// Actions
import { loadAccession, applyFilters, loadAccessionAuditLog } from 'accessions/actions/public';
import {addAccessionToMyList, removeAccessionFromMyList} from 'list/actions/public';
import { addAccessionToMyList, removeAccessionFromMyList } from 'list/actions/public';
import navigateTo from 'actions/navigation';
// Constants
......@@ -39,11 +39,8 @@ import ImageGalleryView from 'repository/ui/c/ImageGalleryView';
import Button from '@material-ui/core/Button/Button';
import AuditedInfo from 'ui/common/AuditedInfo';
import Authorize from 'ui/common/authorized/Authorize';
import TemperatureChart from './c/TemperatureChart';
import PrecipitationChart from './c/PrecipitationChart';
import ClimateTable from './c/ClimateTable';
import BioClimateDisplay from 'accessions/ui/c/BioClimateDisplay';
import PageTitle from 'ui/common/PageTitle';
import ActionButton from 'ui/common/buttons/ActionButton';
const styles = (theme) => ({
pageSection: {
......@@ -137,66 +134,6 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
applyFilters(filter);
}
private makeRange = (variable: number, diff: number) => {
return {
ge: Math.round(variable - diff),
le: Math.round(variable + diff),
};
}
private applyClimateFilters = () => {
const { accession: {details: accession}, applyFilters } = this.props;
// BIO1 = Annual Mean Temperature !!
// BIO2 = Mean Diurnal Range (Mean of monthly (max temp - min temp))
// BIO3 = Isothermality (BIO2/BIO7) (* 100)
// BIO4 = Temperature Seasonality (standard deviation *100)
// BIO5 = Max Temperature of Warmest Month
// BIO6 = Min Temperature of Coldest Month
// BIO7 = Temperature Annual Range (BIO5-BIO6)
// BIO8 = Mean Temperature of Wettest Quarter
// BIO9 = Mean Temperature of Driest Quarter
// BIO10 = Mean Temperature of Warmest Quarter
// BIO11 = Mean Temperature of Coldest Quarter
// BIO12 = Annual Precipitation
// BIO13 = Precipitation of Wettest Month
// BIO14 = Precipitation of Driest Month
// BIO15 = Precipitation Seasonality (Coefficient of Variation)
// BIO16 = Precipitation of Wettest Quarter
// BIO17 = Precipitation of Driest Quarter
// BIO18 = Precipitation of Warmest Quarter !!
// BIO19 = Precipitation of Coldest Quarter !!
const tempDiff = 2;
const filter = {
taxa: {
genus: [ accession.taxonomy.genus ],
// species: [ accession.taxonomy.species ],
},
geo: {
climate: {
// temperature
bio1: this.makeRange(accession.geo.climate.bio1, tempDiff),
// bio2: this.makeRange(accession.geo.climate.bio2, tempDiff),
bio4: this.makeRange(accession.geo.climate.bio4, accession.geo.climate.bio4 * .50),
// bio7: this.makeRange(accession.geo.climate.bio7, tempDiff),
// bio8: this.makeRange(accession.geo.climate.bio8, tempDiff),
// bio9: this.makeRange(accession.geo.climate.bio9, tempDiff),
// bio10: this.makeRange(accession.geo.climate.bio10, tempDiff),
// bio11: this.makeRange(accession.geo.climate.bio11, tempDiff),
// precipitation
bio12: this.makeRange(accession.geo.climate.bio12, accession.geo.climate.bio12 * .25),
// bio13: this.makeRange(accession.geo.climate.bio13, precDif),
// bio14: this.makeRange(accession.geo.climate.bio14, precDif),
// bio15: this.makeRange(accession.geo.climate.bio15, accession.geo.climate.bio15 * .25),
bio18: this.makeRange(accession.geo.climate.bio18, accession.geo.climate.bio18 * .25),
bio19: this.makeRange(accession.geo.climate.bio19, accession.geo.climate.bio19 * .25),
},
},
};
applyFilters(filter);
}
public render() {
const { t, error, uuid, doi, accessions, auditLog, classes } = this.props;
......@@ -405,36 +342,13 @@ class BrowsePage extends React.Component<IBrowsePageProps, any> {
</Properties>
{ hasLatLon &&
<LocationMap locations={ [{ id: accession.geo.id, lat: accession.geo.latitude, lng: accession.geo.longitude }] }/>
<LocationMap locations={ [{ id: accession.geo.id, lat: accession.geo.latitude, lng: accession.geo.longitude }] } />
}
</PageSection>
}
{ accession.geo && accession.geo.climate &&
<PageSection title={ t('accessions.public.p.display.climateAtCollection') }>
<GridContainer className="container-spacing-vertical">
<TemperatureChart halfWidth climate={ accession.geo.climate }/>
<PrecipitationChart halfWidth climate={ accession.geo.climate }/>
</GridContainer>
<div>
<ClimateTable climate={ accession.geo.climate }/>
</div>
</PageSection>
}
{ accession.geo && accession.geo.climate &&
<PageSection title={ t('accessions.public.p.display.additionalInfo') }>
<Properties>
{ [...Array(19).keys()].map((i) => (
<PropertiesItem md numeric key={ `month-${i}` } title={ t(`accessions.climate.bio${i + 1}`) }>
{ accession.geo.climate[`bio${i + 1}`] && Number(accession.geo.climate[`bio${i + 1}`]).toFixed(1) }
</PropertiesItem>
)) }
</Properties>
<div>
<ActionButton action={ this.applyClimateFilters } title="View accessions with similar climate" />
</div>
</PageSection>
<BioClimateDisplay climateData={ accession.geo.climate } extraFilters={ { taxa: { genus: [ accession.taxonomy.genus ] } } } />
}
{ accession.remarks && accession.remarks.length > 0 && <PageSection title={ t('accessions.public.p.display.remarks') }>
......
This diff is collapsed.
import * as React from 'react';
import { translate } from 'react-i18next';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { applyClimateFilters } from 'accessions/actions/public';
// model
import TileClimate from 'model/genesys/TileClimate';
// ui
import {PageSection} from 'ui/layout/PageLayout';
import GridContainer from 'ui/layout/GridContainer';
import ClimateTable from 'accessions/ui/c/ClimateTable';
import PrecipitationChart from 'accessions/ui/c/PrecipitationChart';
import TemperatureChart from 'accessions/ui/c/TemperatureChart';
import { Properties, PropertiesItem } from 'ui/common/Properties';
import ActionButton from 'ui/common/buttons/ActionButton';
const BioClimateDisplay = ({climateData, t, extraFilters, applyClimateFilters, ...rest}: {climateData: TileClimate, t: any, extraFilters?: any, applyClimateFilters: any}) => {
const doFilters = () => {
console.log(`Applying climate filters`, climateData, extraFilters);
applyClimateFilters(climateData, extraFilters);
};
return (
<div>
<PageSection title={ t('accessions.public.p.display.climateAtCollection') } { ...rest }>
<GridContainer className="container-spacing-vertical">
<TemperatureChart halfWidth climate={ climateData }/>
<PrecipitationChart halfWidth climate={ climateData }/>
</GridContainer>
<div>
<ClimateTable climate={ climateData }/>
</div>
</PageSection>
<PageSection title={ t('accessions.public.p.display.additionalInfo') }>
<Properties>
{ [...Array(19).keys()].map((i) => (
<PropertiesItem md numeric key={ `month-${i}` } title={ t(`accessions.climate.bio${i + 1}`) }>
{ climateData[`bio${i + 1}`] && Number(climateData[`bio${i + 1}`]).toFixed(1) }
</PropertiesItem>
)) }
</Properties>
<div style={ { marginTop: '1em' } }>
<h4>{ t('accessions.public.p.display.climateSimilar.title') }</h4>
<p>{ t('accessions.public.p.display.climateSimilar.intro') }</p>
<ActionButton action={ doFilters } title={ t('accessions.public.p.display.climateSimilar.view') } />
</div>
</PageSection>
</div>
);
};
const mapDispatchToProps = (dispatch) => bindActionCreators({
applyClimateFilters,
}, dispatch);
export default connect(null, mapDispatchToProps)(translate()(BioClimateDisplay));
import * as React from 'react';
import { reduxForm } from 'redux-form';
import {translate} from 'react-i18next';
import { ACCESSION_MAP_FILTERFORM } from 'accessions/constants';
import FiltersBlock from 'ui/common/filter/FiltersBlock';
import CollapsibleComponentSearch from 'ui/common/filter/CollapsibleComponentSearch';
import BooleanFilter from 'ui/common/filter/BooleanFilter';
import NumberFilter from 'ui/common/filter/NumberFilter';
import StringFilter from 'ui/common/filter/StringFilter';
import StringArrFilter from 'ui/common/filter/StringArrFilter';
import Accession from 'model/accession/Accession';
import DateFilter from 'ui/common/filter/DateFilter';
import CropFilter from 'crop/ui/c/CropFilter';
const MapAccessionsFilters = ({handleSubmit, initialValues, initialize, t, ...other}) => {
// console.log('AccessionFilters', initialValues);
return (
<FiltersBlock title={ t('accessions.public.f.filtersTitle') } handleSubmit={ handleSubmit } initialize={ initialize } { ...other }>
<CollapsibleComponentSearch title={ t('accessions.public.f.historic') }>
<BooleanFilter name="historic"/>
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('common:f.textSearch') }>
<StringArrFilter name="holder.code" label={ t('accessions.common.instituteCode') } placeholder="NGA039"/>
<StringFilter name="acceNumb" searchType="contains" label={ t('accessions.common.acceNumb') } placeholder="IRGC"/>
<NumberFilter name="seqNo" label={ t('accessions.public.f.seqNumber') } />
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('common:f.dateSearch') }>
<DateFilter name="lastModifiedDate" label={ t('common:f.lastModifiedDate') }/>
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.public.f.crop') }>
<CropFilter/>
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.common.taxonomy') }>
<StringArrFilter name="taxa.genus" label={ t('accessions.common.genus') } placeholder="Hordeum"/>
<StringArrFilter name="taxa.species" label={ t('accessions.common.species') } placeholder="vulgare"/>
<StringFilter name="taxa.subtaxa" searchType="contains" label={ t('accessions.public.f.subtaxon') } placeholder=""/>
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.public.f.originOfMaterial') }>
<StringArrFilter name="origin.iso3" label={ t('accessions.common.countryOfOrigin') } placeholder="SVN"/>
<NumberFilter name="geo.latitude" label={ t('geo.common.latitude') } />
<NumberFilter name="geo.longitude" label={ t('geo.common.longitude') } />
<NumberFilter name="geo.elevation" label={ t('accessions.public.f.elevation') } />
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.public.f.climate') }>
<NumberFilter name="geo.climate.bio1" label={ t('accessions.climate.bio1') } />
<NumberFilter name="geo.climate.bio2" label={ t('accessions.climate.bio2') } />
<NumberFilter name="geo.climate.bio3" label={ t('accessions.climate.bio3') } />
<NumberFilter name="geo.climate.bio4" label={ t('accessions.climate.bio4') } />
<NumberFilter name="geo.climate.bio5" label={ t('accessions.climate.bio5') } />
<NumberFilter name="geo.climate.bio6" label={ t('accessions.climate.bio6') } />
<NumberFilter name="geo.climate.bio7" label={ t('accessions.climate.bio7') } />
<NumberFilter name="geo.climate.bio8" label={ t('accessions.climate.bio8') } />
<NumberFilter name="geo.climate.bio9" label={ t('accessions.climate.bio9') } />
<NumberFilter name="geo.climate.bio10" label={ t('accessions.climate.bio10') } />
<NumberFilter name="geo.climate.bio11" label={ t('accessions.climate.bio11') } />
<NumberFilter name="geo.climate.bio12" label={ t('accessions.climate.bio12') } />
<NumberFilter name="geo.climate.bio13" label={ t('accessions.climate.bio13') } />
<NumberFilter name="geo.climate.bio14" label={ t('accessions.climate.bio14') } />
<NumberFilter name="geo.climate.bio15" label={ t('accessions.climate.bio15') } />
<NumberFilter name="geo.climate.bio16" label={ t('accessions.climate.bio16') } />
<NumberFilter name="geo.climate.bio17" label={ t('accessions.climate.bio17') } />
<NumberFilter name="geo.climate.bio18" label={ t('accessions.climate.bio18') } />
<NumberFilter name="geo.climate.bio19" label={ t('accessions.climate.bio19') } />
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.common.sampStat') }>
<StringArrFilter name="sampStat" options={ Accession.SAMPSTAT } />
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.common.storageType') }>
<StringArrFilter name="storage" options={ Accession.STORAGE } />
</CollapsibleComponentSearch>
<CollapsibleComponentSearch title={ t('accessions.public.f.status') }>
<BooleanFilter name="historic" label={ t('accessions.public.f.historic') } />
<BooleanFilter name="available" label={ t('accessions.public.f.available') } />
<BooleanFilter name="mlsStatus" label={ t('accessions.public.f.mlsStatus') } />
<BooleanFilter name="sgsv" label={ t('accessions.public.f.sgsv') } />
<BooleanFilter name="images" label={ t('accessions.public.f.images') } />
</CollapsibleComponentSearch>
</FiltersBlock>
);
};
export default translate()(reduxForm({
enableReinitialize: true,
destroyOnUnmount: false,
form: ACCESSION_MAP_FILTERFORM,
})(MapAccessionsFilters));
......@@ -29,8 +29,8 @@ const PrecipitationChart = ({ halfWidth = false, climate, t }) => {
scales: {
yAxes: [{
ticks: {
max: Math.round(maxValue + stepSize),
min: Math.round(minValue - stepSize),
max: Math.round(maxValue / stepSize) * stepSize,
min: 0,
stepSize,
},
}],
......@@ -38,7 +38,7 @@ const PrecipitationChart = ({ halfWidth = false, climate, t }) => {
};
return (
<Grid item lg={ halfWidth ? 6 : 12 } md={ 12 }>
<Grid item lg={ halfWidth ? 6 : 12 } md={ 12 } xs={ 12 }>
<div className="mb-15">
<h3 className="pt-5 ml-20"><b>{ t('accessions.climate.monthlyPrecipitation') }</b></h3>
<ColumnChart library={ chartOptions } suffix=" mm" data={ [precipitation] }/>
......
......@@ -44,7 +44,7 @@ const TemperatureChart = ({ halfWidth = false, climate, t }) => {
yAxes: [{
ticks: {
max: Math.round(maxValue + stepSize),
min: 0,
min: Math.round(minValue - stepSize),
stepSize,
},
}],
......@@ -53,7 +53,7 @@ const TemperatureChart = ({ halfWidth = false, climate, t }) => {
return (
<Grid item lg={ halfWidth ? 6 : 12 } md={ 12 }>
<Grid item lg={ halfWidth ? 6 : 12 } md={ 12 } xs={ 12 }>
<div className="mb-15">
<h3 className="pt-5 ml-20"><b>{ t('accessions.climate.monthlyTemp') }</b></h3>
<AreaChart library={ chartOptions } suffix="°C" data={ [minData, meanData, maxData] }/>
......
......@@ -10,35 +10,35 @@ import ClimateFilter from 'model/genesys/ClimateFilter';
* Defined in Swagger as '#/definitions/AccessionFilter'
*/
class AccessionFilter {
public acceNumb: StringFilter;
public active: boolean;
public available: boolean;
public createdBy: number[];
public createdDate: DateFilter;
public acceNumb?: StringFilter;
public active?: boolean;
public available?: boolean;
public createdBy?: number[];
public createdDate?: DateFilter;
public crop?: string[];
public cropName: string;
public doi: string[];
public elevation: NumberFilter;
public geo: { latitude: NumberFilter, longitude: NumberFilter, climate?: ClimateFilter };
public historic: boolean;
public holder: InstituteFilter;
public id: number[];
public lastModifiedBy: number[];
public lastModifiedDate: DateFilter;
public latitude: NumberFilter;
public longitude: NumberFilter;
public mlsStatus: boolean;
public origin: CountryFilter;
public sampStat: number[];
public seqNo: NumberFilter;
public taxa: TaxonomyFilter;
public uuid: string[];
public version: number[];
public sgsv: boolean;
public storage: number[];
public images: boolean;
public cropName?: string;
public doi?: string[];
public elevation?: NumberFilter;
public geo?: { latitude?: NumberFilter, longitude?: NumberFilter, climate?: ClimateFilter };
public historic?: boolean;
public holder?: InstituteFilter;
public id?: number[];
public lastModifiedBy?: number[];
public lastModifiedDate?: DateFilter;
public latitude?: NumberFilter;
public longitude?: NumberFilter;
public mlsStatus?: boolean;
public origin?: CountryFilter;
public sampStat?: number[];
public seqNo?: NumberFilter;
public taxa?: TaxonomyFilter;
public uuid?: string[];
public version?: number[];
public sgsv?: boolean;
public storage?: number[];
public images?: boolean;
public NOT: AccessionFilter;
public NOT?: AccessionFilter;
}
export default AccessionFilter;
......@@ -23,6 +23,10 @@ class ClimateFilter {
public bio13?: NumberFilter;
public bio14?: NumberFilter;
public bio15?: NumberFilter;
public bio16?: NumberFilter;
public bio17?: NumberFilter;
public bio18?: NumberFilter;
public bio19?: NumberFilter;
public prec1?: NumberFilter;
public prec2?: NumberFilter;
......
......@@ -25,7 +25,7 @@ export const AVAILABLE_LAYERS = layerNames.map((layerName) => ({
name: layerName,
title: `accessions.climate.${ layerName }`,
description: `accessions.climateDescription.${ layerName }`,
url: `https://{s}.tile.genesys-pgr.org/worldclim1.4/${ layerName }/{z}/{x}/{y}.png`,
url: `https://{s}.static.genesys-pgr.org/worldclim1.4/${ layerName }/{z}/{x}/{y}.png`,
}));
export default MapLayer;
import * as UrlTemplate from 'url-template';
import axios from 'axios';
import TileClimate from 'model/genesys/TileClimate';
const URL_GET_CURRENT_CLIMATE = UrlTemplate.parse(`https://a.static.genesys-pgr.org/worldclim1.4/json/current/{col}/{row}.json`);
function lon2Col(longitude: number) {
if (longitude == null) {
return null;
}
const columns = 8640;
const ncol = Math.round((columns) * (longitude % 360 + 180) / 360) % columns;
return ncol;
}
function lat2Row(latitude: number) {
if (latitude == null) {
return null;
}
const rows = 4320;
const nrow = Math.round((rows) * (latitude % 180 + 90) / 180) % rows;
return rows - nrow;
}
/*
* Defined in Swagger as 'climate'
*/
class ClimateService {
/**
* getCurrentClimate at /api/v1/climate/current/{latitude},{longitude}
*
* @param latitude latitude
* @param longitude longitude
*/
public static getCurrentClimate(latitude: number, longitude: number): Promise<TileClimate> {
const col = lon2Col(longitude);
const row = lat2Row(latitude);
if (col == null || row == null) {
return Promise.resolve(null);
}
console.log(`(${latitude},${longitude}) = ${col}/${row}.json`);
const apiUrl = URL_GET_CURRENT_CLIMATE.expand({ col, row });
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axios.request({
url: apiUrl,
headers: {
authorization: null,
},
method: 'GET',
...content,
}).then(({ data }) => data as TileClimate);
}
}