Skip to content

Commit

Permalink
Merge 5f18f5c into d3db02a
Browse files Browse the repository at this point in the history
  • Loading branch information
tylerprete committed Mar 24, 2020
2 parents d3db02a + 5f18f5c commit b1a9b67
Show file tree
Hide file tree
Showing 21 changed files with 3,008 additions and 965 deletions.
2 changes: 1 addition & 1 deletion .flowconfig
Expand Up @@ -20,5 +20,5 @@
[strict]

[version]
0.81.0
0.95.1

3 changes: 1 addition & 2 deletions .gitignore
Expand Up @@ -7,8 +7,7 @@ coverage/
.nyc_output/
.npmrc

npm-debug.log
yarn-error.log
*.log

# editor files
.project
Expand Down
2 changes: 1 addition & 1 deletion babel.config.js
Expand Up @@ -26,7 +26,7 @@ module.exports = {
]
},
test: {
presets: ['@babel/env', '@babel/react', '@babel/flow'],
presets: [['@babel/env', { useBuiltIns: 'usage' }], '@babel/react', '@babel/flow'],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from',
Expand Down
20 changes: 12 additions & 8 deletions examples/editor/example.js
@@ -1,8 +1,11 @@
// @flow
/* eslint-env browser */

import React from 'react';
import DeckGL from '@deck.gl/react';
import { EditableGeoJsonLayer } from '@nebula.gl/layers';
import { Toolbox } from '@nebula.gl/editor';
import { DrawPolygonMode } from '@nebula.gl/edit-modes';
import { ViewMode } from '@nebula.gl/edit-modes';
import { StaticMap } from 'react-map-gl';

const MAPBOX_ACCESS_TOKEN =
Expand All @@ -20,15 +23,12 @@ export function Example() {
features: []
});
const [selectedFeatureIndexes] = React.useState([]);
const [mode, setMode] = React.useState(() => DrawPolygonMode);
const [modeConfig, setModeConfig] = React.useState(null);
const [mode, setMode] = React.useState(() => ViewMode);

const layer = new EditableGeoJsonLayer({
data: features,
mode,
modeConfig,
selectedFeatureIndexes,

onEdit: ({ updatedData }) => {
setFeatures(updatedData);
}
Expand All @@ -47,11 +47,15 @@ export function Example() {
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
</DeckGL>
<Toolbox
position="topright"
mode={mode}
features={features}
onSetMode={setMode}
modeConfig={modeConfig}
onSetModeConfig={setModeConfig}
onImport={featureCollection =>
setFeatures({
...features,
features: [...features.features, ...featureCollection.features]
})
}
/>
</>
);
Expand Down
3 changes: 1 addition & 2 deletions examples/editor/package.json
Expand Up @@ -10,8 +10,7 @@
"@deck.gl/react": "^8.0.6",
"react": "^16.8.0",
"react-dom": "^16.4.2",
"react-map-gl": "^5.2.1",
"styled-components": "^4.3.2"
"react-map-gl": "^5.2.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
Expand Down
1,703 changes: 800 additions & 903 deletions examples/editor/yarn.lock

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion modules/editor/package.json
Expand Up @@ -46,6 +46,20 @@
},
"dependencies": {
"@nebula.gl/edit-modes": "^0.17.5",
"react": "^16.8.0"
"react": "^16.8.0",
"@loaders.gl/core": "^2.1.1",
"@loaders.gl/wkt": "^2.1.1",
"@maphubs/tokml": "^0.5.2",
"@tmcw/togeojson": "^3.2.0",
"clipboard-copy": "^3.1.0",
"downloadjs": "^1.4.7",
"react": "^16.8.0",
"react-dropzone": "^10.2.1",
"styled-components": "^4.3.2",
"styled-react-modal": "1.2.4",
"wellknown": "^0.5.0"
},
"devDependencies": {
"sinon": "^9.0.1"
}
}
93 changes: 93 additions & 0 deletions modules/editor/src/editor-modal.js
@@ -0,0 +1,93 @@
// @flow
/* eslint-env browser */

import React from 'react';
import Modal, { ModalProvider } from 'styled-react-modal';
import styled from 'styled-components';

export const Button = styled.button`
display: inline-block;
color: #fff;
background-color: rgb(90, 98, 94);
font-size: 1em;
margin: 0.25em;
padding: 0.375em 0.75em;
border: 1px solid transparent;
border-radius: 0.25em;
display: block;
`;

const StyledModal = Modal.styled`
position: relative;
display: block;
width: 50rem;
height: auto;
max-width: 500px;
margin: 1.75rem auto;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
color: rgb(21, 25, 29);
line-height: 1.5;
text-align: left;
`;

const Content = styled.div`
position: relative;
display: flex;
flex-direction: column;
width: 100%;
pointer-events: auto;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 0.3rem;
outline: 0;
`;

const HeaderRow = styled.div`
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 0.75rem 0.75rem;
border-bottom: 1px solid rgb(222, 226, 230);
`;

const Header = styled.h5`
font-size: 1.25rem;
font-weight: 500;
margin: 0;
`;

export type ModalProps = {
title: any,
content: any,
onClose: () => mixed
};

export function EditorModal(props: ModalProps) {
const [isOpen, setIsOpen] = React.useState(true);

function toggleModal(e) {
if (isOpen) {
props.onClose();
}
setIsOpen(!isOpen);
}

return (
<>
<ModalProvider>
<StyledModal isOpen={isOpen} onBackgroundClick={toggleModal} onEscapeKeydown={toggleModal}>
<Content>
<HeaderRow>
<Header>{props.title}</Header>
</HeaderRow>
{props.content}
</Content>
</StyledModal>
</ModalProvider>
</>
);
}
128 changes: 128 additions & 0 deletions modules/editor/src/export-component.js
@@ -0,0 +1,128 @@
// @flow
/* eslint-env browser */

import React from 'react';
import copy from 'clipboard-copy';
import downloadjs from 'downloadjs';
import styled from 'styled-components';
import { toGeoJson, toKml, toWkt } from './lib/exporter.js';
import { Button } from './editor-modal.js';

const FormatSelect = styled.div`
display: flex;
padding: 0.75rem 0.75rem 0rem 0.75rem;
`;

const ExportArea = styled.div`
box-sizing: border-box;
display: block;
width: auto;
height: auto;
min-height: 300px;
padding: 0rem 1rem;
`;

const ExportData = styled.textarea`
padding: 0px;
width: 100%;
resize: vertical;
min-height: 300px;
max-height: 500px;
border: 1px solid rgb(206, 212, 218);
border-radius: 0.3rem;
font-family: -apple-system, system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1rem;
font-weight: 400;
`;

const FooterRow = styled.div`
display: flex;
justify-content: flex-end;
padding: 0.75rem 0.75rem;
`;

export type ExportComponentProps = {
features: any,
onClose: () => mixed
};

export function ExportComponent(props: ExportComponentProps) {
const geojson = props.features;
const [exportParams, setExportParams] = React.useState(toGeoJson(geojson));
const [format, setFormat] = React.useState('geoJson');

const tooMuch = exportParams.data.length > 500000;

function copyData() {
copy(exportParams.data).then(() => props.onClose());
// TODO Design and add in a notifications banner for errors in the modal.
// .catch(err => {alert(`Error copying to clipboard: `, err)})
}

function downloadData() {
downloadjs(new Blob([exportParams.data]), exportParams.filename, exportParams.mimetype);
props.onClose();
}

return (
<>
<FormatSelect>
<strong style={{ padding: '0.5rem 0.25rem' }}>Format:</strong>
<Button
style={{
backgroundColor: format === 'geoJson' ? 'rgb(0, 105, 217)' : 'rgb(90, 98, 94)'
}}
onClick={() => {
setExportParams(toGeoJson(geojson));
setFormat('geoJson');
}}
>
GeoJson
</Button>
<Button
style={{
backgroundColor: format === 'kml' ? 'rgb(0, 105, 217)' : 'rgb(90, 98, 94)'
}}
onClick={() => {
setExportParams(toKml(geojson));
setFormat('kml');
}}
>
KML
</Button>
<Button
style={{
backgroundColor: format === 'wkt' ? 'rgb(0, 105, 217)' : 'rgb(90, 98, 94)'
}}
onClick={() => {
setExportParams(toWkt(geojson));
setFormat('wkt');
}}
>
WKT
</Button>
</FormatSelect>
<ExportArea>
<ExportData
readOnly={true}
style={tooMuch ? { fontStyle: 'italic', padding: '0.75rem 0rem' } : {}}
value={
tooMuch
? 'Too much data to display. Download or Copy to clipboard instead.'
: exportParams.data
}
/>
</ExportArea>
<FooterRow>
<Button style={{ backgroundColor: 'rgb(0, 105, 217)' }} onClick={downloadData}>
Download
</Button>
<Button style={{ backgroundColor: 'rgb(0, 105, 217)' }} onClick={copyData}>
Copy
</Button>
<Button onClick={props.onClose}>Cancel</Button>
</FooterRow>
</>
);
}
22 changes: 22 additions & 0 deletions modules/editor/src/export-modal.js
@@ -0,0 +1,22 @@
// @flow
/* eslint-env browser */

import React from 'react';
import type { AnyGeoJson } from '@nebula.gl/edit-modes';
import { EditorModal } from './editor-modal.js';
import { ExportComponent } from './export-component.js';

export type ExportModalProps = {
features: AnyGeoJson,
onClose: () => mixed
};

export function ExportModal(props: ExportModalProps) {
return (
<EditorModal
onClose={props.onClose}
title={'Export'}
content={<ExportComponent features={props.features} onClose={props.onClose} />}
/>
);
}

0 comments on commit b1a9b67

Please sign in to comment.