This commit is contained in:
Andrey Bakhvalov 2018-10-22 17:47:43 +03:00
parent 1c548efc7e
commit 3d206fbdb0
10 changed files with 124 additions and 80 deletions

View File

@ -1,12 +1,5 @@
{ {
"parser": "babel-eslint", "extends": ["react-app", "airbnb"],
"extends": ["airbnb"],
"plugins": ["import", "react"],
"env": {
"browser": true,
"node": true,
"jest": true
},
"rules": { "rules": {
"arrow-parens": [ "arrow-parens": [
"warn", "warn",
@ -16,7 +9,6 @@
} }
], ],
"comma-dangle": ["error", "never"], "comma-dangle": ["error", "never"],
"function-paren-newline": ["error", "consistent"],
"jsx-quotes": ["error", "prefer-single"], "jsx-quotes": ["error", "prefer-single"],
"max-len": [ "max-len": [
"error", "error",
@ -27,13 +19,6 @@
} }
], ],
"no-return-assign": "warn", "no-return-assign": "warn",
"no-underscore-dangle": [
"error",
{
"allowAfterThis": true,
"allow": ["_id"]
}
],
"quotes": ["error", "single"], "quotes": ["error", "single"],
"react/button-has-type": "off", "react/button-has-type": "off",
"react/destructuring-assignment": "off", "react/destructuring-assignment": "off",

View File

@ -78,7 +78,7 @@ BEGIN
sel_zones.locationid = trips_by_hour.pulocationid sel_zones.locationid = trips_by_hour.pulocationid
AND cast(trips_by_hour.pickup_datetime AS DATE) >= date_from AND cast(trips_by_hour.pickup_datetime AS DATE) >= date_from
AND cast(trips_by_hour.pickup_datetime AS DATE) <= date_to AND cast(trips_by_hour.pickup_datetime AS DATE) <= date_to
AND ((extract (HOUR FROM trips_by_hour.pickup_datetime) = in_hour) OR (in_hour IS NULL)) AND ((extract (HOUR FROM trips_by_hour.pickup_datetime) = in_hour) OR (in_hour = -1))
) )
GROUP BY GROUP BY
sel_zones.locationid sel_zones.locationid

View File

@ -0,0 +1,13 @@
import React from 'react';
const CaptionElement = ({ date, localeUtils, locale }) => {
const months = localeUtils.getMonths(locale);
return (
<div className='DayPicker-Caption'>
{months[date.getMonth()]}
</div>
);
};
export default CaptionElement;

View File

@ -0,0 +1 @@
export { default } from './CaptionElement';

View File

@ -1,9 +1,9 @@
import styled from 'styled-components'; import styled from 'styled-components';
export default styled.div` export default styled.div`
margin-bottom: 14px; margin-bottom: 30px;
font-size: 16px; font-size: 16px;
line-height: 1.44; line-height: 1.44;
color: #dadfee; color: rgba(218,223,238,0.9);
`; `;

View File

@ -3,11 +3,16 @@ import DayPicker, { DateUtils } from 'react-day-picker';
import { debounce } from 'debounce'; import { debounce } from 'debounce';
import 'react-day-picker/lib/style.css'; import 'react-day-picker/lib/style.css';
import { JAN, DEC } from '../../../config/constants';
import dateConverter from '../../../utils/dateConverter';
import Container from './Container'; import Container from './Container';
import Title from './Title'; import Title from './Title';
import Description from './Description'; import Description from './Description';
import Separator from './Separator';
import Range from './Range'; import Range from './Range';
import DayPickerContainer from './DayPicker'; import DayPickerContainer from './DayPicker';
import CaptionElement from './CaptionElement';
import TimePicker from './TimePicker'; import TimePicker from './TimePicker';
import AvgTime from './AvgTime'; import AvgTime from './AvgTime';
import Input from './Input'; import Input from './Input';
@ -27,7 +32,9 @@ class Filters extends PureComponent {
debounce(this.props.changeFilter('hour', e.target.value), 300); debounce(this.props.changeFilter('hour', e.target.value), 300);
}; };
dateConverter = date => date && `${date.getDate()}.${date.getMonth() + 1}`; setAverageTime = () => {
this.props.changeFilter('hour', -1);
};
toggleDayPicker = () => { toggleDayPicker = () => {
this.setState( this.setState(
@ -36,9 +43,11 @@ class Filters extends PureComponent {
}; };
render() { render() {
const { range, hour } = this.props; const { range: { from, to }, hour } = this.props;
const { from, to } = range;
const modifiers = { start: from, end: to }; const modifiers = { start: from, end: to };
const isAvgHour = hour === -1;
const dateFrom = dateConverter(from);
const dateTo = dateConverter(to);
return ( return (
<Container> <Container>
@ -48,8 +57,9 @@ class Filters extends PureComponent {
<Description> <Description>
Conducted from an area Conducted from an area
</Description> </Description>
<Separator />
<Range onClick={this.toggleDayPicker}> <Range onClick={this.toggleDayPicker}>
{`${this.dateConverter(from)} ${this.dateConverter(to)}`} {`${dateFrom} ${dateTo}`}
</Range> </Range>
{this.state.isDayPickerEnabled && ( {this.state.isDayPickerEnabled && (
<DayPickerContainer> <DayPickerContainer>
@ -58,26 +68,17 @@ class Filters extends PureComponent {
selectedDays={[from, { from, to }]} selectedDays={[from, { from, to }]}
modifiers={modifiers} modifiers={modifiers}
onDayClick={this.handleDayClick} onDayClick={this.handleDayClick}
captionElement={({ date, localeUtils, locale }) => { captionElement={CaptionElement}
const months = localeUtils.getMonths(locale); initialMonth={JAN}
fromMonth={JAN}
return ( toMonth={DEC}
<div className='DayPicker-Caption'>
{months[date.getMonth()]}
</div>
);
}}
initialMonth={new Date(2017, 0)}
fromMonth={new Date(2017, 0)}
toMonth={new Date(2017, 11)}
/> />
</DayPickerContainer> </DayPickerContainer>
)} )}
<TimePicker> <TimePicker>
<AvgTime <AvgTime
isEnabled={hour === -1} isEnabled={isAvgHour}
onClick={() => this.props.changeFilter('hour', -1)} onClick={this.setAverageTime}
> >
AVG AVG
</AvgTime> </AvgTime>
@ -89,7 +90,7 @@ class Filters extends PureComponent {
step='1' step='1'
onChange={this.changeTime} onChange={this.changeTime}
/> />
{hour !== -1 && ( {!isAvgHour && (
<div> <div>
{`${hour}:00`} {`${hour}:00`}
</div> </div>

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
export default styled.div`
height: 9px;
border-top: solid 1px rgba(87,94,119,0.9);
border-bottom: solid 1px rgba(87,94,119,0.9);
margin-bottom: 30px;
`;

View File

@ -1,6 +1,10 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import mapboxgl from 'mapbox-gl'; import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css'; import 'mapbox-gl/dist/mapbox-gl.css';
import { MAPBOX_STYLE, MAPBOX_TOKEN } from '../../config/constants';
import dateConverter from '../../utils/dateConverter';
import Container from './Container'; import Container from './Container';
import Filters from './Filters'; import Filters from './Filters';
@ -19,37 +23,33 @@ class Map extends PureComponent {
}; };
componentDidMount() { componentDidMount() {
mapboxgl.accessToken = 'pk.eyJ1IjoibWFydGlucHJvamVjdDEiLCJhIjoiY2ptdW93MXZrMDNjMTNrcGhmNTJ1ZGljdCJ9.9fC5LXUepNAYTKu8O162OA'; mapboxgl.accessToken = MAPBOX_TOKEN;
this.map = new mapboxgl.Map({ this.map = new mapboxgl.Map({
container: 'map', container: 'map',
style: 'mapbox://styles/martinproject1/cjnfxj6053wz32rq8r9sija4o' style: MAPBOX_STYLE
}); });
this.nav = new mapboxgl.NavigationControl(); this.nav = new mapboxgl.NavigationControl();
this.map.scrollZoom.disable(); this.map.scrollZoom.disable();
this.map.addControl(this.nav, 'top-right'); this.map.addControl(this.nav, 'top-right');
this.map.on('load', this.mapOnLoad); this.map.on('load', this.mapOnLoad);
} }
componentDidUpdate() { componentDidUpdate() {
const { range, hour } = this.state; const queryParams = this.getQueryParams();
const { from, to } = range; const newStyleUrl = `/tiles/rpc/public.get_trips.json?${queryParams}`;
if (!from || !to) return;
const dateFrom = this.dateConverter(from);
const dateTo = this.dateConverter(to);
const queryParams = encodeURI(
`date_from=${dateFrom}&date_to=${dateTo}&hour=${hour}`
);
const newStyle = this.map.getStyle(); const newStyle = this.map.getStyle();
newStyle.sources['public.get_trips'].url = `/tiles/rpc/public.get_trips.json?${queryParams}`;
newStyle.sources['public.get_trips'].url = newStyleUrl;
this.map.setStyle(newStyle); this.map.setStyle(newStyle);
} }
mapOnLoad = () => { mapOnLoad = () => {
const queryParams = this.getQueryParams();
this.map.addSource('public.get_trips', { this.map.addSource('public.get_trips', {
type: 'vector', type: 'vector',
url: '/tiles/rpc/public.get_trips.json?date_from=01.01.2017&date_to=02.01.2017&hour=9' url: `/tiles/rpc/public.get_trips.json?${queryParams}`
}); });
this.map.addLayer({ this.map.addLayer({
id: 'trips', id: 'trips',
@ -59,39 +59,65 @@ class Map extends PureComponent {
paint: { paint: {
'fill-extrusion-height': [ 'fill-extrusion-height': [
'interpolate', 'interpolate',
['exponential', 1.3], ['linear'],
['get', 'trips'], ['get', 'trips'],
17, 0,
10, 10,
1204, 3,
100, 30,
2526, 70,
200, 70,
4738, 90,
150,
300,
300,
2500,
400, 400,
6249, 8000,
600 600,
12000,
800,
20000,
1100,
30000,
1600,
55000,
2000,
76000,
3000
], ],
'fill-extrusion-color': [ 'fill-extrusion-color': [
'interpolate', 'interpolate',
['exponential', 1.3], ['linear'],
['get', 'trips'], ['get', 'trips'],
0, 0,
'#f2a8ff', '#fff0f0',
2, 3,
'#f2a8ff', '#ffdade',
15, 70,
'#dc70ff', '#ffc4d1',
26, 90,
'#bc39fe', '#ffaec9',
540, 300,
'#9202fd', '#ff98c5',
900, 2500,
'#6002c5' '#f982c5',
8000,
'#ee6cc8',
12000,
'#de58ce',
20000,
'#c847d7',
30000,
'#ab3ae1',
55000,
'#8233ed',
76000,
'#3434f9'
], ],
'fill-extrusion-opacity': 0.75 'fill-extrusion-opacity': 0.75
} }
}); }, 'place-town');
}; };
changeFilter = (filter, value) => { changeFilter = (filter, value) => {
@ -101,12 +127,13 @@ class Map extends PureComponent {
})); }));
}; };
dateConverter = (date) => { getQueryParams = () => {
const year = date.getFullYear(); const { range: { from, to }, hour } = this.state;
const month = date.getMonth() + 1;
const day = date.getDate();
return `${month}.${day}.${year}`; const dateFrom = `${dateConverter(from)}.2017`;
const dateTo = `${dateConverter(to)}.2017`;
return encodeURI(`date_from=${dateFrom}&date_to=${dateTo}&hour=${hour}`);
}; };
render() { render() {

4
src/config/constants.js Normal file
View File

@ -0,0 +1,4 @@
export const MAPBOX_TOKEN = 'pk.eyJ1IjoibWFydGlucHJvamVjdDEiLCJhIjoiY2ptdW93MXZrMDNjMTNrcGhmNTJ1ZGljdCJ9.9fC5LXUepNAYTKu8O162OA';
export const MAPBOX_STYLE = 'mapbox://styles/martinproject1/cjnfxj6053wz32rq8r9sija4o';
export const JAN = new Date(2017, 0);
export const DEC = new Date(2017, 11);

View File

@ -0,0 +1,5 @@
export default (date) => {
if (!date) return '';
return `${date.getDate()}.${date.getMonth() + 1}`;
};