kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
156 lines (140 loc) • 5.18 kB
JavaScript
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import React, {useCallback, useMemo} from 'react';
import styled from 'styled-components';
import Slider from 'components/common/slider/slider';
import {BottomWidgetInner} from 'components/common/styled-components';
import PlaybackControlsFactory from './playback-controls';
import FloatingTimeDisplayFactory from './floating-time-display';
import {snapToMarks, datetimeFormatter} from 'utils/data-utils';
import {DEFAULT_TIME_FORMAT} from 'constants/default-settings';
const SliderWrapper = styled.div`
display: flex;
position: relative;
flex-grow: 1;
margin-right: 24px;
margin-left: 24px;
`;
const AnimationWidgetInner = styled.div`
position: relative;
display: flex;
align-items: center;
height: 32px;
.playback-controls {
margin-left: -8px;
margin-right: 16px;
}
`;
const StyledDomain = styled.div.attrs({
className: 'animation-control__time-domain'
})`
color: ${props => props.theme.titleTextColor};
font-weight: 400;
font-size: 10px;
`;
AnimationControlFactory.deps = [PlaybackControlsFactory, FloatingTimeDisplayFactory];
function AnimationControlFactory(PlaybackControls, FloatingTimeDisplay) {
const AnimationControl = ({
isAnimatable,
isAnimating,
resetAnimation,
toggleAnimation,
setLayerAnimationTime,
updateAnimationSpeed,
animationConfig
}) => {
const {
currentTime,
domain,
speed,
step,
timeSteps,
timeFormat,
timezone,
defaultTimeFormat
} = animationConfig;
const onSlider1Change = useCallback(
val => {
if (Array.isArray(timeSteps)) {
setLayerAnimationTime(snapToMarks(val, timeSteps));
// TODO: merge slider in to avoid this step
} else if (val >= domain[0] && val <= domain[1]) {
setLayerAnimationTime(val);
}
},
[domain, timeSteps, setLayerAnimationTime]
);
const dateFunc = useMemo(() => {
const hasUserFormat = typeof timeFormat === 'string';
const currentFormat = (hasUserFormat ? timeFormat : defaultTimeFormat) || DEFAULT_TIME_FORMAT;
return datetimeFormatter(timezone)(currentFormat);
}, [timeFormat, defaultTimeFormat, timezone]);
const timeStart = useMemo(() => (domain ? dateFunc(domain[0]) : ''), [domain, dateFunc]);
const timeEnd = useMemo(() => (domain ? dateFunc(domain[1]) : ''), [domain, dateFunc]);
return (
<BottomWidgetInner className="bottom-widget--inner">
<AnimationWidgetInner className="animation-widget--inner">
<PlaybackControls
className="animation-control-playpause"
startAnimation={toggleAnimation}
isAnimating={isAnimating}
pauseAnimation={toggleAnimation}
resetAnimation={resetAnimation}
speed={speed}
isAnimatable={isAnimatable}
updateAnimationSpeed={updateAnimationSpeed}
/>
<StyledDomain className="domain-start">
<span>{timeStart}</span>
</StyledDomain>
<SliderWrapper className="animation-control__slider">
<Slider
showValues={false}
isRanged={false}
step={step}
minValue={domain ? domain[0] : 0}
maxValue={domain ? domain[1] : 1}
value1={currentTime}
onSlider1Change={onSlider1Change}
enableBarDrag={true}
/>
</SliderWrapper>
<StyledDomain className="domain-end">
<span>{timeEnd}</span>
</StyledDomain>
</AnimationWidgetInner>
<FloatingTimeDisplay
currentTime={currentTime}
defaultTimeFormat={defaultTimeFormat}
timeFormat={timeFormat}
timezone={timezone}
/>
</BottomWidgetInner>
);
};
AnimationControl.defaultProps = {
toggleAnimation: () => {},
updateAnimationSpeed: () => {},
animationControlProps: {},
animationConfig: {}
};
return AnimationControl;
}
export default AnimationControlFactory;