diff --git a/src/client/components/facet_bar/FacetBar.js b/src/client/components/facet_bar/FacetBar.js index fd91c4597609818ff87df4418d67633a64aacc27..4912885f35e0e2bc799450ca93a5e93afa589892 100644 --- a/src/client/components/facet_bar/FacetBar.js +++ b/src/client/components/facet_bar/FacetBar.js @@ -4,6 +4,7 @@ import { withStyles } from '@material-ui/core/styles'; import HierarchicalFacet from './HierarchicalFacet'; import TextFacet from './TextFacet'; import SliderFacet from './SliderFacet'; +import RangeFacet from './RangeFacet'; import Paper from '@material-ui/core/Paper'; import FacetHeader from './FacetHeader'; import FacetInfo from './FacetInfo'; @@ -44,6 +45,9 @@ const styles = theme => ({ five: { height: 150, }, + six: { + height: 180, + }, ten: { height: 357, }, @@ -137,6 +141,21 @@ class FacetBar extends React.Component { /> ); break; + case 'integerFilterRange': + facetComponent = ( + <RangeFacet + facetID={facetID} + facet={facet} + facetClass={this.props.facetClass} + resultClass={this.props.resultClass} + facetUpdateID={facetUpdateID} + fetchFacet={this.props.fetchFacet} + someFacetIsFetching={someFacetIsFetching} + updateFacetOption={this.props.updateFacetOption} + dataType='integer' + /> + ); + break; default: facetComponent = ( <HierarchicalFacet diff --git a/src/client/components/facet_bar/FacetHelpers.js b/src/client/components/facet_bar/FacetHelpers.js new file mode 100644 index 0000000000000000000000000000000000000000..78e74279d0332a6f573cf70a0c1c3cda9668643f --- /dev/null +++ b/src/client/components/facet_bar/FacetHelpers.js @@ -0,0 +1,31 @@ +export const ISOStringToYear = str => { + let year = null; + if (str.charAt(0) == '-') { + year = parseInt(str.substring(0,5)); + } else { + year = parseInt(str.substring(0,4)); + } + return year; +}; + +export const YearToISOString = ({ year, start }) => { + const abs = Math.abs(year); + let s = year.toString(); + let negative = false; + if (s.charAt(0) == '-') { + s = s.substring(1); + negative = true; + } + if (abs < 10) { + s = '000' + s; + } + if (abs >= 10 && abs < 100) { + s = '00' + s; + } + if (abs >= 100 && abs < 1000) { + s = '0' + s; + s = negative ? s = '-' + s : s; + } + s = start ? s + '-01-01' : s + '-12-31'; + return s; +}; diff --git a/src/client/components/facet_bar/RangeFacet.js b/src/client/components/facet_bar/RangeFacet.js new file mode 100644 index 0000000000000000000000000000000000000000..abb2cf72bfa382278c555cba41e771b1a2096bda --- /dev/null +++ b/src/client/components/facet_bar/RangeFacet.js @@ -0,0 +1,176 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import purple from '@material-ui/core/colors/purple'; +import { withStyles } from '@material-ui/core/styles'; +import TextField from '@material-ui/core/TextField'; +import Button from '@material-ui/core/Button'; +import { YearToISOString, ISOStringToYear } from './FacetHelpers'; + +const styles = theme => ({ + root: { + height: '100%', + display: 'flex', + }, + textFields: { + marginRight: theme.spacing(2) + }, + textField: { + display: 'block' + }, + applyButton: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + paddingTop: theme.spacing(1.5), + }, + spinnerContainer: { + display: 'flex', + width: '100%', + height: '100%', + alignItems: 'center', + justifyContent: 'center' + }, +}); + +class RangeFacet extends Component { + constructor(props) { + super(props); + this.state = { + min: '', + max: '' + }; + } + + componentDidMount = () => { + const { isFetching, min, max } = this.props.facet; + if (!isFetching && (min == null || max == null)) { + this.props.fetchFacet({ + facetClass: this.props.facetClass, + facetID: this.props.facetID, + }); + } + } + + handleMinChange = event => { + this.setState({ min: event.target.value }); + } + + handleMaxChange = event => { + this.setState({ max: event.target.value }); + } + + handleApplyOnClick = event => { + let { min, max } = this.state; + let values = [ min, max ]; + if (this.props.dataType === 'ISOString') { + values[0] = YearToISOString({ year: values[0], start: true }); + values[1] = YearToISOString({ year: values[1], start: false }); + } + this.props.updateFacetOption({ + facetClass: this.props.facetClass, + facetID: this.props.facetID, + option: this.props.facet.filterType, + value: values + }); + event.preventDefault(); + } + + render() { + const { classes, someFacetIsFetching } = this.props; + const { isFetching, min, max } = this.props.facet; + let domain = null; + let values = null; + if (isFetching || min == null || max == null) { + return( + <div className={classes.spinnerContainer}> + <CircularProgress style={{ color: purple[500] }} thickness={5} /> + </div> + ); + } else { + if (this.props.dataType === 'ISOString') { + const minYear = this.ISOStringToYear(min); + const maxYear = this.ISOStringToYear(max); + domain = [ minYear, maxYear ]; + if (this.props.facet.timespanFilter == null) { + values = domain; + } else { + const { start, end } = this.props.facet.timespanFilter; + values = [ this.ISOStringToYear(start), this.ISOStringToYear(end) ]; + } + } else if (this.props.dataType === 'integer') { + domain = [ parseInt(min), parseInt(max) ]; + if (this.props.facet.integerFilter == null) { + values = domain; + } else { + const { start, end } = this.props.facet.integerFilter; + values = [ start, end ]; + } + } + + return ( + <div className={classes.root}> + <div className={classes.textFields}> + <TextField + id="standard-number" + label="Min" + disabled={someFacetIsFetching} + value={this.state.min} + onChange={this.handleMinChange} + type="number" + variant="outlined" + className={classes.textField} + InputLabelProps={{ + shrink: true, + }} + margin="normal" + /> + <TextField + id="standard-number" + label="Max" + disabled={someFacetIsFetching} + value={this.state.max} + onChange={this.handleMaxChange} + type="number" + variant="outlined" + className={classes.textField} + InputLabelProps={{ + shrink: true, + }} + margin="normal" + /> + </div> + <div className={classes.applyButton}> + <Button + variant="contained" + color="primary" + className={classes.button} + onClick={this.handleApplyOnClick} + disabled={this.state.min === '' && this.state.max === ''} + > + apply + </Button> + </div> + </div> + ); + } + } +} + + +RangeFacet.propTypes = { + classes: PropTypes.object.isRequired, + facetID: PropTypes.string.isRequired, + facet: PropTypes.object.isRequired, + facetClass: PropTypes.string, + resultClass: PropTypes.string, + fetchFacet: PropTypes.func, + someFacetIsFetching: PropTypes.bool.isRequired, + updateFacetOption: PropTypes.func, + facetUpdateID: PropTypes.number, + updatedFilter: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), + updatedFacet: PropTypes.string, + dataType: PropTypes.string.isRequired +}; + +export default withStyles(styles)(RangeFacet); diff --git a/src/client/components/facet_bar/SliderFacet.js b/src/client/components/facet_bar/SliderFacet.js index 3ce2255214f49c4f817c3250dd9dafbdabebdb77..d46ae90e8cd7a363580e4a461911e123591673b0 100644 --- a/src/client/components/facet_bar/SliderFacet.js +++ b/src/client/components/facet_bar/SliderFacet.js @@ -5,6 +5,7 @@ import purple from '@material-ui/core/colors/purple'; import { withStyles } from '@material-ui/core/styles'; import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider'; import { Handle, Track, Tick, TooltipRail } from './SliderComponents'; +import { YearToISOString, ISOStringToYear } from './FacetHelpers'; const sliderRootStyle = { position: 'relative', @@ -42,8 +43,8 @@ class SliderFacet extends Component { handleSliderOnChange = values => { if (this.props.dataType === 'ISOString') { - values[0] = this.YearToISOString({ year: values[0], start: true }); - values[1] = this.YearToISOString({ year: values[1], start: false }); + values[0] = YearToISOString({ year: values[0], start: true }); + values[1] = YearToISOString({ year: values[1], start: false }); } this.props.updateFacetOption({ facetClass: this.props.facetClass, @@ -53,38 +54,6 @@ class SliderFacet extends Component { }); } - ISOStringToYear = str => { - let year = null; - if (str.charAt(0) == '-') { - year = parseInt(str.substring(0,5)); - } else { - year = parseInt(str.substring(0,4)); - } - return year; - } - - YearToISOString = ({ year, start }) => { - const abs = Math.abs(year); - let s = year.toString(); - let negative = false; - if (s.charAt(0) == '-') { - s = s.substring(1); - negative = true; - } - if (abs < 10) { - s = '000' + s; - } - if (abs >= 10 && abs < 100) { - s = '00' + s; - } - if (abs >= 100 && abs < 1000) { - s = '0' + s; - s = negative ? s = '-' + s : s; - } - s = start ? s + '-01-01' : s + '-12-31'; - return s; - } - render() { const { classes, someFacetIsFetching } = this.props; const { isFetching, min, max } = this.props.facet; @@ -98,14 +67,14 @@ class SliderFacet extends Component { ); } else { if (this.props.dataType === 'ISOString') { - const minYear = this.ISOStringToYear(min); - const maxYear = this.ISOStringToYear(max); + const minYear = ISOStringToYear(min); + const maxYear = ISOStringToYear(max); domain = [ minYear, maxYear ]; if (this.props.facet.timespanFilter == null) { values = domain; } else { const { start, end } = this.props.facet.timespanFilter; - values = [ this.ISOStringToYear(start), this.ISOStringToYear(end) ]; + values = [ ISOStringToYear(start), ISOStringToYear(end) ]; } } else if (this.props.dataType === 'integer') { domain = [ parseInt(min), parseInt(max) ]; diff --git a/src/client/components/perspectives/PerspectiveArrayMMM.js b/src/client/components/perspectives/PerspectiveArrayMMM.js index 85eb30ddfe02bfced5ef78ddb3689b8fe32520df..7fbf265d0496fde1f159799fcb9e4a2efd301c73 100644 --- a/src/client/components/perspectives/PerspectiveArrayMMM.js +++ b/src/client/components/perspectives/PerspectiveArrayMMM.js @@ -62,7 +62,7 @@ export const perspectiveArr = [ </React.Fragment> , perspectiveDescHeight: 99, - defaultActiveFacets: new Set(['prefLabel']), + defaultActiveFacets: new Set(['prefLabel', 'height']), tabs: [ { id: 'table', diff --git a/src/client/reducers/helpers.js b/src/client/reducers/helpers.js index 7ad055861f66aa14b1d8738e4d9a0df6647863d4..8fcad69c681d7283c8d683ec61ddcf05badb569d 100644 --- a/src/client/reducers/helpers.js +++ b/src/client/reducers/helpers.js @@ -73,7 +73,8 @@ export const updateFacetOption = (state, action) => { 'spatialFilter', 'textFilter', 'timespanFilter', - 'integerFilter' + 'integerFilter', + 'integerFilterRange' ]; if (filterTypes.includes(action.option)) { return updateFacetFilter(state, action); @@ -137,7 +138,8 @@ const updateFacetFilter = (state, action) => { } }; } - } else if (oldFacet.filterType === 'integerFilter') { + } else if (oldFacet.filterType === 'integerFilter' + || oldFacet.filterType === 'integerFilterRange') { if (value == null) { newFacet = { ...state.facets[facetID], diff --git a/src/client/reducers/manuscriptsFacets.js b/src/client/reducers/manuscriptsFacets.js index 553d97b8896842c3261ded9141c2ebbeeed24b79..c35491a8c53650f91ca0df8a95c574a4caf894d7 100644 --- a/src/client/reducers/manuscriptsFacets.js +++ b/src/client/reducers/manuscriptsFacets.js @@ -251,15 +251,15 @@ export const INITIAL_STATE = { distinctValueCount: 0, values: [], flatValues: [], - sortBy: 'instanceCount', - sortDirection: 'desc', - sortButton: true, + //sortBy: 'instanceCount', + //sortDirection: 'desc', + sortButton: false, spatialFilterButton: false, isFetching: false, - searchField: true, - containerClass: 'three', + //searchField: false, + containerClass: 'five', type: 'integer', - filterType: 'integerFilter', + filterType: 'integerFilterRange', integerFilter: null, priority: 11 }, diff --git a/src/server/sparql/Filters.js b/src/server/sparql/Filters.js index 60087e47c770802b9b467f941e9bae2c95c93694..4c56414a1c98e801c7996918eeddb5fb3b0d1740 100644 --- a/src/server/sparql/Filters.js +++ b/src/server/sparql/Filters.js @@ -88,6 +88,7 @@ export const generateConstraintsBlock = ({ }); break; case 'integerFilter': + case 'integerFilterRange': filterStr += generateIntegerFilter({ facetClass: facetClass, facetID: c.id,