diff --git a/.gitignore b/.gitignore
index 8725630bf8..9b34857e57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ umd/
typedoc/
+*/**/node_modules
*/**/yarn.lock
yarn-error.log
*/**/package-lock.json
diff --git a/examples/demo-app/package.json b/examples/demo-app/package.json
index 24ce8092a6..b93b57e450 100644
--- a/examples/demo-app/package.json
+++ b/examples/demo-app/package.json
@@ -56,6 +56,7 @@
"babel-loader": "^8.0.0",
"babel-plugin-module-resolver": "^3.0.0",
"babel-plugin-transform-builtin-extend": "^1.1.0",
+ "gh-pages": "^3.1.0",
"webpack": "^4.29.0",
"webpack-cli": "^3.2.1",
"webpack-dev-middleware": "^3.5.1",
@@ -63,4 +64,4 @@
"webpack-hot-middleware": "^2.24.3",
"webpack-stats-plugin": "^0.2.1"
}
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index 391eea3a1c..4a921f730e 100644
--- a/package.json
+++ b/package.json
@@ -115,6 +115,7 @@
"global": "^4.3.0",
"h3-js": "^3.1.0",
"html-webpack-plugin": "^4.3.0",
+ "hubble.gl": "1.1.0-alpha.4",
"keymirror": "^0.1.1",
"lodash.clonedeep": "^4.0.1",
"lodash.curry": "^4.1.1",
diff --git a/src/components/common/animation-control/animation-control.js b/src/components/common/animation-control/animation-control.js
index c50e88846e..c91e4afa48 100644
--- a/src/components/common/animation-control/animation-control.js
+++ b/src/components/common/animation-control/animation-control.js
@@ -19,17 +19,20 @@
// THE SOFTWARE.
import React from 'react';
-import styled from 'styled-components';
+import styled, { withTheme } from 'styled-components';
import moment from 'moment';
import Slider from 'components/common/slider/slider';
-import {BottomWidgetInner} from 'components/common/styled-components';
+import {BottomWidgetInner, Button} from 'components/common/styled-components';
import SpeedControlFactory from './speed-control';
import AnimationPlaybacksFactory from './playback-controls';
import FloatingTimeDisplayFactory from './floating-time-display';
import AnimationControllerFactory from './animation-controller';
import {snapToMarks} from 'utils/data-utils';
import {DEFAULT_TIME_FORMAT, ANIMATION_TYPE} from 'constants';
+import HubbleExport from 'components/hubble-export';
+import {connect as keplerGlConnect} from 'connect/keplergl-connect';
+
const SliderWrapper = styled.div`
display: flex;
@@ -160,6 +163,9 @@ function AnimationControlFactory(
buttonHeight={BUTTON_HEIGHT}
/>
+
+
+
diff --git a/src/components/hubble-export.js b/src/components/hubble-export.js
new file mode 100644
index 0000000000..8f14f71e99
--- /dev/null
+++ b/src/components/hubble-export.js
@@ -0,0 +1,92 @@
+// Copyright (c) 2020 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, {Component} from 'react';
+import {ThemeProvider, withTheme} from 'styled-components';
+
+import {connect as keplerGlConnect} from 'connect/keplergl-connect';
+import RenderSettingsModal from './render-settings-modal';
+import {Button} from 'components/common/styled-components';
+import {theme} from '../styles';
+
+
+// TODO this isn't DRY. Comes from https://github.com/keplergl/kepler.gl/blob/995024e86880fefb0624af4ed1e98d3879558336/src/components/kepler-gl.js
+function mapStateToProps(state = {}, props) {
+ return {
+ ...props,
+ visState: state.visState,
+ mapStyle: state.mapStyle,
+ mapState: state.mapState,
+ uiState: state.uiState,
+ providerState: state.providerState
+ // isOpen: state.isOpen TODO
+ };
+}
+
+function makeMapDispatchToProps() {
+ // const getActionCreators = makeGetActionCreators();
+ const mapDispatchToProps = (dispatch, ownProps) => {
+ // const groupedActionCreators = getActionCreators(dispatch, ownProps);
+
+ return {
+ // TODO Put action creator and return here
+ // ...groupedActionCreators,
+ dispatch
+ };
+ };
+
+ return mapDispatchToProps;
+}
+
+class HubbleExport extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ isOpen: false
+ };
+ }
+ handleClose() {this.setState({isOpen: false})} // X button in Modal UI was clicked
+
+ handleExport() { // Export button in Kepler UI was clicked
+ this.setState(state => ({
+ isOpen: true
+ }));
+ // stop rendering in bg
+ // setState
+ // pop up modal if isOpen. If false, closes modal TODO put function into render
+ // all the data is passed through and can use in deck/hubble components
+ return REACHED
+ }
+
+ render() {
+ // console.log(this.props)
+ console.log(this.state)
+ return (
+
+
+
+ this.handleExport()}>Export {/* anonymous function to bind state onclick */}
+
+ )
+ }
+};
+
+export default keplerGlConnect(mapStateToProps, makeMapDispatchToProps)(withTheme(HubbleExport));
+
diff --git a/src/components/map-container.js b/src/components/map-container.js
index 6cc116fc19..59193a0604 100644
--- a/src/components/map-container.js
+++ b/src/components/map-container.js
@@ -287,12 +287,13 @@ export default function MapContainerFactory(MapPopover, MapControl, Editor) {
layerHoverProp.compareType = interactionConfig.tooltip.config.compareType;
}
}
- const commonProp = {
- onClose: this._onCloseMapPopover,
- mapW: mapState.width,
- mapH: mapState.height,
- zoom: mapState.zoom
- };
+
+ const commonProp = {
+ onClose: this._onCloseMapPopover,
+ mapW: mapState.width,
+ mapH: mapState.height,
+ zoom: mapState.zoom
+ };
return (
@@ -483,8 +484,8 @@ export default function MapContainerFactory(MapPopover, MapControl, Editor) {
};
const isEdit = uiState.mapControls.mapDraw.active;
-
return (
+
+
+
'pointer' : undefined}
transitionDuration={TRANSITION_DURATION}
- onMouseMove={this.props.visStateActions.onMouseMove}
+ onMouseMove={this.props.visStateActions.onMouseMove}
>
- {this._renderDeckOverlay(layersToRender)}
+
+
+
+ {this._renderDeckOverlay(layersToRender)}
{this._renderMapboxOverlays(layersToRender)}
+
+
{
+ const {defaultSettingsPos, bottomBuffer, settingsHeight} = this.props;
+ if (showSettings === false || !this.root || !this.root.current) return defaultSettingsPos;
+ const {sidePanelInnerPadding = 16, sidePanel = {}, sidePanelScrollBarWidth = 10} = theme;
+ const sidePanelLeft = (sidePanel.margin || {}).left || 20;
+ const offsetX = sidePanelInnerPadding + sidePanelLeft + sidePanelScrollBarWidth;
+ // find component Root position
+ const bounding = this.root.current.getBoundingClientRect();
+ const {x, y, width} = bounding;
+
+ // set the top so it won't collide with bottom widget
+ const top =
+ y + settingsHeight <= window.innerHeight - bottomBuffer
+ ? y
+ : window.innerHeight - bottomBuffer - settingsHeight;
+
+ return {top: `${top}px`, left: `${x + width + offsetX}px`};
+ });
+
+ modalStylesSelector = createSelector(
+ this.themeSelector,
+ this.settingsPosSelector,
+ (theme, settingsPos) => ({
+ content: {
+ top: 'auto',
+ left: 'auto',
+ right: `calc(50% - ${DIMENSIONS.sidePanel.width / 2}px)`,
+ bottom: '50%',
+ transform: 'translate(50%, 50%)',
+ padding: '0px 0px 0px 0px',
+ border: 0,
+ backgroundColor: theme.sidePanelBg,
+ borderRadius: theme.panelBorderRadius || '2px'
+ },
+ overlay: {
+ backgroundColor: 'rgba(0, 0, 0, 0)'
+ }
+ // content: {
+ // top: 0,
+ // left: 0,
+ // border: 0,
+ // right: 'auto',
+ // bottom: 'auto',
+ // padding: '0px 0px 0px 0px',
+ // borderRadius: theme.panelBorderRadius || '2px'
+ // },
+ // overlay: {
+ // ...settingsPos,
+ // right: 'auto',
+ // bottom: 'auto',
+ // backgroundColor: 'rgba(0, 0, 0, 0)'
+ // }
+ })
+ );
+
+ render() {
+ const {isOpen, handleClose} = this.props;
+
+ const modalStyles = this.modalStylesSelector(this.props);
+ return (
+
+ {this.root.current ? (
+ {
+ // React modal issue: https://github.com/reactjs/react-modal/issues/769
+ // failed to execute removeChild on parent node when it is already unmounted
+ return (
+ this.root.current || {
+ removeChild: () => {},
+ appendChild: () => {}
+ }
+ );
+ }}
+ >
+ {handleClose()}} mapData={this.props.mapData}/>
+
+ ) : null}
+
+ );
+ }
+}
+
+export default withTheme(RenderSettingsModal);
\ No newline at end of file
diff --git a/src/components/render-settings-panel.js b/src/components/render-settings-panel.js
new file mode 100644
index 0000000000..9e0504cf99
--- /dev/null
+++ b/src/components/render-settings-panel.js
@@ -0,0 +1,323 @@
+// Copyright (c) 2020 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, {Component} from 'react';
+import styled, {withTheme} from 'styled-components';
+import {Button, Input} from 'kepler.gl/components/common/styled-components';
+import {Delete} from 'kepler.gl/components/common/icons';
+import ItemSelector from 'kepler.gl/components/common/item-selector/item-selector';
+import {Scene} from 'components/scene';
+
+import {
+ SettingsController,
+ preview,
+ setFileNameDeckAdapter,
+ render
+ } from 'components/render/settings-controller';
+
+import {setKeyframes} from 'components/render/keyframes';
+
+const DEFAULT_BUTTON_HEIGHT = '32px';
+const DEFAULT_BUTTON_WIDTH = '64px';
+const DEFAULT_PADDING = '32px';
+const DEFAULT_ROW_GAP = '16px';
+
+const IconButton = styled(Button)`
+ padding: 0;
+ svg {
+ margin: 0;
+ }
+`;
+
+const PanelCloseInner = styled.div`
+ display: flex;
+ justify-content: flex-end;
+ padding: ${DEFAULT_PADDING} ${DEFAULT_PADDING} 0 ${DEFAULT_PADDING};
+`;
+
+const PanelClose = ({buttonHeight, handleClose}) => (
+
+ {handleClose()}}>
+
+
+
+);
+
+const StyledTitle = styled.div`
+ color: ${props => props.theme.titleTextColor};
+ font-size: 20px;
+ font-weight: 400;
+ line-height: ${props => props.theme.lineHeight};
+ padding: 0 ${DEFAULT_PADDING} 16px ${DEFAULT_PADDING};
+`;
+
+const StyledSection = styled.div`
+ align-self: center;
+ color: ${props => props.theme.labelColor};
+ font-weight: 500;
+ font-size: 13px;
+ margin-top: ${DEFAULT_PADDING};
+ margin-bottom: ${DEFAULT_ROW_GAP};
+`;
+
+const StyledLabelCell = styled.div`
+ align-self: center;
+ color: ${props => props.theme.labelColor};
+ font-weight: 400;
+ font-size: 11px;
+`;
+
+const StyledValueCell = styled.div`
+ align-self: center;
+ color: ${props => props.theme.textColor};
+ font-weight: 500;
+ font-size: 11px;
+ padding: 0 12px;
+`;
+
+const PanelBodyInner = styled.div`
+ padding: 0 ${DEFAULT_PADDING};
+ display: grid;
+ grid-template-columns: 480px auto;
+ grid-column-gap: 20px;
+`;
+
+const InputGrid = styled.div`
+ display: grid;
+ grid-template-columns: 88px auto;
+ grid-template-rows: repeat(
+ ${props => props.rows},
+ ${props => (props.rowHeight ? props.rowHeight : '34px')}
+ );
+ grid-row-gap: ${DEFAULT_ROW_GAP};
+`;
+
+const PanelBody = ({mapData, setMediaType, setCamera, setFileName, setQuality, setTimeStamps, settingsData}) => (
+
+
+
+
+
+ Video Effects
+
+ Timestamp {/* TODO add functionality */}
+
+ Camera {/* TODO add functionality */}
+
+
+ Export Settings {/* TODO add functionality */}
+
+ File Name
+
+ Media Type {/* TODO add functionality */}
+
+ Quality {/* TODO add functionality */}
+
+
+
+ Duration {/* TODO add functionality */}
+ 00:00:30
+ File Size {/* TODO add functionality */}
+ 36 MB
+
+
+
+);
+
+const PanelFooterInner = styled.div`
+ display: flex;
+ justify-content: space-between;
+ margin-top: ${DEFAULT_ROW_GAP};
+ padding: ${DEFAULT_PADDING};
+`;
+
+const ButtonGroup = styled.div`
+ display: flex;
+`;
+
+const PanelFooter = ({handleClose, settingsData, preview}) => (
+
+ (preview(settingsData.adapter))}
+ >
+ Preview
+
+
+ {handleClose()}}
+ >
+ Cancel {/* TODO add functionality to close */}
+
+ render(settingsData, settingsData.adapter)}
+ >
+ Render
+
+
+
+);
+
+const Panel = styled.div`
+ width: ${props => props.settingsWidth}px;
+`;
+
+class RenderSettingsPanel extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ mediaType: "WebM Video",
+ camera: "None",
+ fileName: "Video Name",
+ quality: "High (720p)",
+ timestamps: "None"
+ };
+
+ this.setMediaTypeState = this.setMediaTypeState.bind(this);
+ this.setCamera = this.setCamera.bind(this);
+ this.setFileName = this.setFileName.bind(this);
+ this.setQuality = this.setQuality.bind(this);
+ this.setTimeStamps = this.setTimeStamps.bind(this);
+
+ this.mapDataGlobal = this.props.mapData;
+ this.settingsController = ;
+
+ }
+
+ static defaultProps = {
+ settingsWidth: 980,
+ buttonHeight: '16px',
+ };
+
+ setMediaTypeState(media){
+ this.setState({
+ mediaType: media
+ });
+ }
+ setCamera(option){
+ this.setState({
+ camera: option
+ });
+ setKeyframes(option, this.settingsController.props.adapter, this.mapdataGlobal);
+ }
+ setFileName(name){
+ this.setState({
+ fileName: name.target.value
+ });
+ setFileNameDeckAdapter(name.target.value);
+ }
+ setQuality(resolution){
+ this.setState({
+ quality: resolution
+ });
+ }
+ setTimeStamps(time){
+ this.setState({
+ timestamps: time
+ });
+ }
+
+ render() {
+
+ const adapter = this.settingsController.props.adapter;
+
+ const {buttonHeight, settingsWidth, handleClose} = this.props;
+ const settingsData = {
+ mediaType : this.state.mediaType,
+ camera : this.state.camera,
+ fileName: this.state.fileName,
+ resolution: this.state.quality,
+ time: this.state.timestamps,
+ adapter: adapter
+ }
+
+ return (
+
+
+ {/* handleClose for X button */}
+ Export Video
+
+ {/* handleClose for Cancel button */}
+
+ );
+ }
+}
+
+export default withTheme(RenderSettingsPanel);
\ No newline at end of file
diff --git a/src/components/render/encoder-settings.js b/src/components/render/encoder-settings.js
new file mode 100644
index 0000000000..8198e8e46b
--- /dev/null
+++ b/src/components/render/encoder-settings.js
@@ -0,0 +1,18 @@
+import React, {Component} from 'react';
+
+export const encoderSettings = {
+ framerate: 30,
+ webm: {
+ quality: 0.8
+ },
+ jpeg: {
+ quality: 2
+ },
+ gif: {
+ sampleInterval: 1000
+ },
+ webm:{
+ quality: 1.5
+ },
+ filename: "Default Video Name" + " " + moment().format(DEFAULT_TIME_FORMAT).toString()
+ };
\ No newline at end of file
diff --git a/src/components/render/keyframes.js b/src/components/render/keyframes.js
new file mode 100644
index 0000000000..37c6e4e874
--- /dev/null
+++ b/src/components/render/keyframes.js
@@ -0,0 +1,126 @@
+export function setKeyframes(cameraType, adapter, mapdataGlobal){
+ adapter.scene.keyframes.camera._lastTime = 0;
+ adapter.scene.keyframes.camera.factor = 0;
+
+
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+
+ if(cameraType === 'Orbit (90º)'){
+ // How to reset the camera to its initial position?
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 90;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'Orbit (180º)'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 180;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'Orbit (360º)'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 360;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'North to South'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude + 25;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude - 25;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'South to North'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude - 25;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude + 25;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'East to West'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude + 25;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude - 25;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'West to East'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude - 25;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude + 25;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+ }else if(cameraType === 'Zoom Out'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom - 2;
+ }else if(cameraType === 'Zoom In'){
+ adapter.scene.keyframes.camera.values[0].bearing = 0;
+ adapter.scene.keyframes.camera.values[0].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[0].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[0].pitch = 0;
+ adapter.scene.keyframes.camera.values[0].zoom = mapdataGlobal.mapState.zoom;
+
+ adapter.scene.keyframes.camera.values[1].bearing = 0;
+ adapter.scene.keyframes.camera.values[1].latitude = mapdataGlobal.mapState.latitude;
+ adapter.scene.keyframes.camera.values[1].longitude = mapdataGlobal.mapState.longitude;
+ adapter.scene.keyframes.camera.values[1].pitch = 0;
+ adapter.scene.keyframes.camera.values[1].zoom = mapdataGlobal.mapState.zoom + 2;
+ }
+
+
+ console.log("adapter", adapter);
+ }
\ No newline at end of file
diff --git a/src/components/render/settings-controller.js b/src/components/render/settings-controller.js
new file mode 100644
index 0000000000..4c6c006af4
--- /dev/null
+++ b/src/components/render/settings-controller.js
@@ -0,0 +1,130 @@
+import React, {Component} from 'react';
+import {DeckScene, CameraKeyframes} from '@hubble.gl/core';
+import {easing} from 'popmotion';
+import {DeckAdapter} from 'hubble.gl';
+
+import {
+ WebMEncoder,
+ JPEGSequenceEncoder,
+ PNGSequenceEncoder,
+ PreviewEncoder,
+ GifEncoder
+ } from '@hubble.gl/core';
+
+import {DEFAULT_TIME_FORMAT} from 'constants';
+import moment from 'moment';
+
+let mapDataGlobal = null;
+
+const encoderSettings = {
+ framerate: 30,
+ webm: {
+ quality: 0.8
+ },
+ jpeg: {
+ quality: 2
+ },
+ gif: {
+ sampleInterval: 1000
+ },
+ webm:{
+ quality: 1
+ },
+ filename: "Default Video Name" + " " + moment().format(DEFAULT_TIME_FORMAT).toString()
+ };
+
+export class SettingsController extends Component{
+ constructor(props) {
+ super(props);
+
+ // I need to pass mapDataGlobal to be used here
+ }
+
+ static defaultProps = {
+ adapter: new DeckAdapter(sceneBuilder)
+ };
+
+}
+
+ function sceneBuilder(animationLoop) {
+ console.log(" this.props.mapDataGlobal", mapDataGlobal);
+ const data = {};
+ const keyframes = {
+ camera: new CameraKeyframes({
+ timings: [0, 1000],
+ keyframes: [
+ {
+ longitude: mapDataGlobal.mapState.longitude,
+ latitude: mapDataGlobal.mapState.latitude,
+ zoom: mapDataGlobal.mapState.zoom,
+ pitch: 0,
+ bearing: 0
+ /* longitude: 11,
+ latitude: 0,
+ zoom: 2,
+ pitch: 0,
+ bearing: 0*/
+ },
+ {
+ longitude: mapDataGlobal.mapState.longitude,
+ latitude: mapDataGlobal.mapState.latitude,
+ zoom: mapDataGlobal.mapState.zoom,
+ bearing: 0,
+ pitch: 0
+ /* longitude: 11,
+ latitude: 0,
+ zoom: 2,
+ pitch: 0,
+ bearing: 0*/
+ }
+ ],
+ easings: [easing.easeInOut]
+ })
+ };
+ animationLoop.timeline.attachAnimation(keyframes.camera);
+
+ // TODO: Figure out how to set up the size
+ return new DeckScene({
+ animationLoop,
+ keyframes,
+ lengthMs: 1000,
+ data,
+ width: 480,
+ height: 460
+ });
+ }
+
+ export function preview(adapter) {
+ adapter.render(PreviewEncoder, encoderSettings, ()=>{});
+ }
+
+ export function setFileNameDeckAdapter(name){
+ encoderSettings.filename = name + " " + moment().format(DEFAULT_TIME_FORMAT).toString();
+ }
+
+ export function render(settingsdata, adapter){
+
+ // setResolution(settingsdata.resolution); // Remove this
+
+ if (settingsdata.mediaType === 'WebM Video') {
+ adapter.render(WebMEncoder, encoderSettings, () => {}); // Onstop callback
+ } else if (settingsdata.mediaType === 'PNG Sequence') {
+ adapter.render(PNGSequenceEncoder, encoderSettings, () => {});
+ } else if (settingsdata.mediaType === 'JPEG Sequence') {
+ adapter.render(JPEGSequenceEncoder, encoderSettings, () => {});
+ }
+ // preview();
+ }
+
+ /*function setResolution(resolution){
+ if(resolution === 'Good (540p)'){
+ adapter.scene.width = 960;
+ adapter.scene.height = 540;
+ }else if(resolution === 'High (720p)'){
+ adapter.scene.width = 1280;
+ adapter.scene.height = 720;
+ }else if(resolution === 'Highest (1080p)'){
+ adapter.scene.width = 1920;
+ adapter.scene.height = 1080;
+ }
+}*/
diff --git a/src/components/scene.js b/src/components/scene.js
new file mode 100644
index 0000000000..4d02b68247
--- /dev/null
+++ b/src/components/scene.js
@@ -0,0 +1,228 @@
+// Copyright (c) 2020 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, {Component, useState, useRef} from 'react';
+
+//Map Component
+import DeckGL from '@deck.gl/react';
+import {OVERLAY_TYPE} from 'layers/base-layer';
+import MapboxGLMap from 'react-map-gl';
+import {transformRequest} from 'utils/map-style-utils/mapbox-utils';
+
+import {MapView} from '@deck.gl/core';
+import {TileLayer} from '@deck.gl/geo-layers';
+import {BitmapLayer, PathLayer} from '@deck.gl/layers';
+
+import { load } from "@loaders.gl/core";
+
+const MAPBOX_TOKEN = 'pk.eyJ1IjoicGlvbmVlci1tZSIsImEiOiJjanA0OXMwM2IwcW5qM2tvYnAyYndpdXMxIn0.bqxGkqM2ozOVT57GuVzEjw';
+const TRANSITION_DURATION = 0;
+
+const INITIAL_VIEW_STATE = {
+ latitude: 47.65,
+ longitude: 7,
+ zoom: 4.5,
+ maxZoom: 20,
+ maxPitch: 89,
+ bearing: 0
+};
+
+
+const tileLayer = new TileLayer({
+
+ autoHighlight : true,
+ highlightColor: [60, 60, 60, 40],
+ opacity: 1,
+ // https://wiki.openstreetmap.org/wiki/Zoom_levels
+ minZoom: 0,
+ maxZoom: 19,
+ tileSize: 256,
+
+
+ data: [
+ `http://{d90016be4e11c76b57d0311404f546f06afbae25}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png`
+ ],
+
+
+ renderSubLayers: props => {
+ const {
+ bbox: { west, south, east, north }
+ } = props.tile;
+
+ return new BitmapLayer(props, {
+ data: [],
+ image: props.data,
+ bounds: [west, south, east, north]
+ });
+ }
+})
+
+
+/* global window */
+const devicePixelRatio = (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
+
+export class Scene extends Component {
+
+ constructor(props) {
+ super(props);
+
+ this.mapData = this.props.mapData;
+
+ //this.adapter = new DeckAdapter(this.props.sceneBuilder);
+ }
+
+
+ _renderLayer = (overlays, idx) => {
+ const datasets = this.mapData.visState.datasets;
+ const layers = this.mapData.visState.layers;
+ const layerData = this.mapData.visState.layerData;
+ const hoverInfo = this.mapData.visState.hoverInfo;
+ const clicked = this.mapData.visState.clicked;
+ const mapState = this.mapData.mapState;
+ const interactionConfig = this.mapData.visState.interactionConfig;
+ const animationConfig = this.mapData.visState.animationConfig;
+
+ const layer = layers[idx];
+ const data = layerData[idx];
+ const {gpuFilter} = datasets[layer.config.dataId] || {};
+
+ const objectHovered = clicked || hoverInfo;
+ const layerCallbacks = {
+ onSetLayerDomain: val => this._onLayerSetDomain(idx, val)
+ };
+
+ // Layer is Layer class
+ const layerOverlay = layer.renderLayer({
+ data,
+ gpuFilter,
+ idx,
+ interactionConfig,
+ layerCallbacks,
+ mapState,
+ animationConfig,
+ objectHovered
+ });
+ return overlays.concat(layerOverlay || []);
+ };
+
+ // Testing purposes
+ print(prop){
+ console.log("this.deckgl", prop);
+ };
+
+ // Is this being used right?
+ componentDidMount() {
+ this.forceUpdate();
+ }
+
+ // This is provisional -
+ // [ADD] TileLayer to the array of layers
+
+
+
+
+
+
+
+ // interactionConfig,
+ render() {
+ // console.log("all props ", this.props.mapData);
+
+ const mapStyle = this.mapData.mapStyle;
+ const mapState = this.mapData.mapState;
+ const layers = this.mapData.visState.layers;
+ const layerData = this.mapData.visState.layerData;
+ const layerOrder = this.mapData.visState.layerOrder;
+ const animationConfig = this.mapData.visState.animationConfig;
+ const useDevicePixels = false;
+ //Map data
+ const mapboxApiAccessToken = this.mapData.mapStyle.mapboxApiAccessToken;
+ const mapboxApiUrl = this.mapData.mapStyle.mapboxApiUrl;
+ // define trip and geojson layers
+ let deckGlLayers = [];
+
+
+
+
+ // wait until data is ready before render data layers
+ if (layerOrder && layerOrder.length) {
+ // last layer render first
+ deckGlLayers = layerOrder
+ .slice()
+ .reverse()
+ .filter(
+ idx => layers[idx].overlayType === OVERLAY_TYPE.deckgl && layers[idx].id
+ )
+ .reduce(this._renderLayer, []);
+ }
+
+ /* deckGlLayers[2] = deckGlLayers[1];
+ deckGlLayers[1] = deckGlLayers[0]
+ deckGlLayers[0] = tileLayer; */
+
+
+
+ console.log("deckGlLayers ", deckGlLayers);
+
+ // MapboxGLMap
+ const mapProps = {
+ ...mapState,
+ preserveDrawingBuffer: true,
+ mapboxApiAccessToken,
+ mapboxApiUrl,
+ transformRequest
+ };
+
+ const style = {
+ position: 'relative'
+ }
+ console.log("adapter from scene ", this.props.adapter);
+
+ return (
+
+ {this.deckgl={current:r}}}
+ viewState={mapState}
+ id="default-deckgl-overlay2"
+ layers={deckGlLayers}
+ useDevicePixels={useDevicePixels}
+ style={style}
+ views={new MapView({repeat: true})}
+ /* onBeforeRender={this._onBeforeRender} // Not yet
+ onHover={visStateActions.onLayerHover} // Not yet
+ onClick={visStateActions.onLayerClick}*/ // Not yet
+ {...this.props.adapter.getProps(this.deckgl, () => {}, () => {this.forceUpdate()})}
+ >
+
+ 'pointer' : undefined}
+ transitionDuration={TRANSITION_DURATION}
+ >
+
+
+
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 751d5a3634..60727feff4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1356,6 +1356,23 @@
dependencies:
"@hapi/hoek" "^8.3.0"
+"@hubble.gl/core@1.1.0-alpha.4":
+ version "1.1.0-alpha.4"
+ resolved "https://registry.yarnpkg.com/@hubble.gl/core/-/core-1.1.0-alpha.4.tgz#85d2ab543e7dc8c9cad61aaad3b2ee32d9aad860"
+ integrity sha512-QMW3SF0AYuvR2sARkmTGPV4gvVsMh0MIqytbdkxkqqLODv1O9HLtnpUSGvE3Z/6u0J02mmHqPIECRWKAAAj4NA==
+ dependencies:
+ "@loaders.gl/core" "^2.1.6"
+ "@loaders.gl/video" "2.2.0-alpha.1"
+ "@luma.gl/engine" "^8.2.0"
+ downloadjs "^1.4.7"
+ popmotion "^8.6.10"
+ webm-writer "^0.2.2"
+
+"@hubble.gl/react@1.1.0-alpha.4":
+ version "1.1.0-alpha.4"
+ resolved "https://registry.yarnpkg.com/@hubble.gl/react/-/react-1.1.0-alpha.4.tgz#a63f06ffd107df32f4297bae8b7659d27a214c3a"
+ integrity sha512-808DCV9LWshTa4wMYYgy6vqFBlxg7mu0EpXQNlItubHwFEeBUCIWbh2BS1lrhU9QBMUC2d6c85PFlzLmZx6yaQ==
+
"@icons/material@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
@@ -2243,6 +2260,14 @@
"@babel/runtime" "^7.3.1"
"@loaders.gl/loader-utils" "2.2.5"
+"@loaders.gl/core@^2.1.6":
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/@loaders.gl/core/-/core-2.2.8.tgz#fb2060f3b90d3babe0de2a128fc5227f921c08ad"
+ integrity sha512-PM74zQA6Kn6NJCMoRdEDENy9jQWQyMkICKZ6o8UGa6/oi3dD4LO5GhFZSwU6W/Lxl/IeUwaZBQ3MqfT3aXA0Dg==
+ dependencies:
+ "@babel/runtime" "^7.3.1"
+ "@loaders.gl/loader-utils" "2.2.8"
+
"@loaders.gl/csv@^2.2.5":
version "2.2.5"
resolved "https://registry.yarnpkg.com/@loaders.gl/csv/-/csv-2.2.5.tgz#4667cbfb62b98d918a1c4e233bfb880939ab74fb"
@@ -2293,7 +2318,7 @@
"@babel/runtime" "^7.3.1"
"@probe.gl/stats" "^3.3.0"
-"@loaders.gl/loader-utils@^2.2.5":
+"@loaders.gl/loader-utils@2.2.8", "@loaders.gl/loader-utils@^2.1.3", "@loaders.gl/loader-utils@^2.2.5":
version "2.2.8"
resolved "https://registry.yarnpkg.com/@loaders.gl/loader-utils/-/loader-utils-2.2.8.tgz#9f12f3460260b15e961fa46c3d3c867d7bf48bee"
integrity sha512-3F2VgxJPxjuZwAr8fDBkZzx3Wg275XdVaWnyYQ3uyZQ22yGEkrzKc+TlgcqSrxbO5pHrtS5PdS7dmyoJo2+Bdg==
@@ -2361,6 +2386,14 @@
"@math.gl/web-mercator" "^3.2.0"
"@probe.gl/stats" "^3.3.0"
+"@loaders.gl/video@2.2.0-alpha.1":
+ version "2.2.0-alpha.1"
+ resolved "https://registry.yarnpkg.com/@loaders.gl/video/-/video-2.2.0-alpha.1.tgz#1bb09e9e507605a72c6e8a13b34926b69c717191"
+ integrity sha512-4NDe3fNPOTS4MvPxlxrbqr/kKgkB9tOVY2in/s/oYBo0uiDK+WSU0AztnyKxF1b/EsHzTEIzhOEhjvSwbgRQgQ==
+ dependencies:
+ "@loaders.gl/loader-utils" "^2.1.3"
+ gifshot "^0.4.5"
+
"@luma.gl/constants@8.2.0", "@luma.gl/constants@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@luma.gl/constants/-/constants-8.2.0.tgz#0789c629edbb8b69b7f810ae10c91501b97c634b"
@@ -2377,7 +2410,7 @@
"@luma.gl/shadertools" "8.2.0"
"@luma.gl/webgl" "8.2.0"
-"@luma.gl/engine@8.2.0":
+"@luma.gl/engine@8.2.0", "@luma.gl/engine@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@luma.gl/engine/-/engine-8.2.0.tgz#e598b723639619e00cff8acaf4af39de4d9fb61f"
integrity sha512-HxlwU66TCJzMCY+wuxiyapiGFEp0HrRqg2m2fj8K5h5PBYMjDZSrs2JuDoOz97oFVALfujAEw74OX9pFr5uiRg==
@@ -2674,6 +2707,22 @@
dependencies:
"@types/node" ">= 8"
+"@popmotion/easing@^1.0.1":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@popmotion/easing/-/easing-1.0.2.tgz#17d925c45b4bf44189e5a38038d149df42d8c0b4"
+ integrity sha512-IkdW0TNmRnWTeWI7aGQIVDbKXPWHVEYdGgd5ZR4SH/Ty/61p63jCjrPxX1XrR7IGkl08bjhJROStD7j+RKgoIw==
+
+"@popmotion/popcorn@^0.4.4":
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/@popmotion/popcorn/-/popcorn-0.4.4.tgz#a5f906fccdff84526e3fcb892712d7d8a98d6adc"
+ integrity sha512-jYO/8319fKoNLMlY4ZJPiPu8Ea8occYwRZhxpaNn/kZsK4QG2E7XFlXZMJBsTWDw7I1i0uaqyC4zn1nwEezLzg==
+ dependencies:
+ "@popmotion/easing" "^1.0.1"
+ framesync "^4.0.1"
+ hey-listen "^1.0.8"
+ style-value-types "^3.1.7"
+ tslib "^1.10.0"
+
"@probe.gl/stats@3.2.1":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@probe.gl/stats/-/stats-3.2.1.tgz#4e95c75513229ebb01384045e89524a466c022eb"
@@ -6159,6 +6208,11 @@ dotignore@~0.1.2:
dependencies:
minimatch "^3.0.4"
+downloadjs@^1.4.7:
+ version "1.4.7"
+ resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c"
+ integrity sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw=
+
draco3d@^1.3.4:
version "1.3.6"
resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.3.6.tgz#e4d9e7d846637775328c903721c932b953dce331"
@@ -7378,6 +7432,14 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
+framesync@^4.0.0, framesync@^4.0.1:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.0.4.tgz#79c42c0118f26821c078570db0ff81fb863516a2"
+ integrity sha512-mdP0WvVHe0/qA62KG2LFUAOiWLng5GLpscRlwzBxu2VXOp6B8hNs5C5XlFigsMgrfDrr2YbqTsgdWZTc4RXRMQ==
+ dependencies:
+ hey-listen "^1.0.8"
+ tslib "^1.10.0"
+
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -7617,6 +7679,11 @@ gif-encoder@~0.4.1:
dependencies:
readable-stream "~1.1.9"
+gifshot@^0.4.5:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/gifshot/-/gifshot-0.4.5.tgz#e3cb570203a3b139ff3069d7578098a29c03b0f8"
+ integrity sha1-48tXAgOjsTn/MGnXV4CYopwDsPg=
+
git-raw-commits@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5"
@@ -8139,6 +8206,11 @@ he@1.2.x, he@^1.1.0, he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+hey-listen@^1.0.5, hey-listen@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
+ integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
+
highlight.js@^10.0.0:
version "10.0.3"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.0.3.tgz#5effcc58420f113f279a0badb8ac50c4be06e63b"
@@ -8428,6 +8500,14 @@ https-proxy-agent@^4.0.0:
agent-base "5"
debug "4"
+hubble.gl@1.1.0-alpha.4:
+ version "1.1.0-alpha.4"
+ resolved "https://registry.yarnpkg.com/hubble.gl/-/hubble.gl-1.1.0-alpha.4.tgz#0393a11d1272af35ca69950e86d25dce315682b5"
+ integrity sha512-Xb7rKzBG4fPuUgTQ/sPkFucidwG4Ld2CkkXGGh6ikC2OAOrUs3IffhCmeOwecPkg66tBrULOfpfT8XDnViYbZQ==
+ dependencies:
+ "@hubble.gl/core" "1.1.0-alpha.4"
+ "@hubble.gl/react" "1.1.0-alpha.4"
+
human-signals@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
@@ -12498,6 +12578,19 @@ pngjs@^3.0.0, pngjs@^3.3.3:
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
+popmotion@^8.6.10:
+ version "8.7.3"
+ resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-8.7.3.tgz#330a77fd8b288f0e8f930e3d3f351d6eb4897860"
+ integrity sha512-OcpS/V9sCJjrKiVfp3JB5kp5SBqefZ4RvM9GBLYgv0YbULxv9S5METP9ueVJxSClR3yrfFEY2pLWTWKLn/EUfg==
+ dependencies:
+ "@popmotion/easing" "^1.0.1"
+ "@popmotion/popcorn" "^0.4.4"
+ framesync "^4.0.0"
+ hey-listen "^1.0.5"
+ style-value-types "^3.1.7"
+ stylefire "^7.0.1"
+ tslib "^1.10.0"
+
portfinder@^1.0.25:
version "1.0.25"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca"
@@ -15084,6 +15177,14 @@ strong-log-transformer@^2.0.0:
minimist "^1.2.0"
through "^2.3.4"
+style-value-types@^3.1.7:
+ version "3.1.7"
+ resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.1.7.tgz#3d7d3cf9cb9f9ee86c00e19ba65d6a181a0db33a"
+ integrity sha512-jPaG5HcAPs3vetSwOJozrBXxuHo9tjZVnbRyBjxqb00c2saIoeuBJc1/2MtvB8eRZy41u/BBDH0CpfzWixftKg==
+ dependencies:
+ hey-listen "^1.0.8"
+ tslib "^1.10.0"
+
styled-components@^4.1.3:
version "4.4.1"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2"
@@ -15103,6 +15204,17 @@ styled-components@^4.1.3:
stylis-rule-sheet "^0.0.10"
supports-color "^5.5.0"
+stylefire@^7.0.1:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/stylefire/-/stylefire-7.0.3.tgz#9120ecbb084111788e0ddaa04074799750f20d1d"
+ integrity sha512-Q0l7NSeFz/OkX+o6/7Zg3VZxSAZeQzQpYomWmIpOehFM/rJNMSLVX5fgg6Q48ut2ETNKwdhm97mPNU643EBCoQ==
+ dependencies:
+ "@popmotion/popcorn" "^0.4.4"
+ framesync "^4.0.0"
+ hey-listen "^1.0.8"
+ style-value-types "^3.1.7"
+ tslib "^1.10.0"
+
stylis-rule-sheet@^0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
@@ -16498,6 +16610,11 @@ webidl-conversions@^5.0.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
+webm-writer@^0.2.2:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/webm-writer/-/webm-writer-0.2.5.tgz#cca049f392c5e47a328d83590e983f97e8f28fda"
+ integrity sha512-wzHOIZkvKDOC/GJdOalYlzH0NypLvlaXdUhliTkH7Y5akdmBl0TOVmRTPFW3yfw+cAYS3RMtu5nCYIGovDUsvw==
+
webpack-bundle-analyzer@^3.0.3, webpack-bundle-analyzer@^3.3.2:
version "3.6.0"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.0.tgz#39b3a8f829ca044682bc6f9e011c95deb554aefd"