Skip to content

Full Mapbox support #961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'brace/theme/textmate';
// https://github.com/plotly/react-chart-editor#mapbox-access-tokens
import ACCESS_TOKENS from '../accessTokens';

import {customConfigTest} from '../src/__stories__';
// import {customConfigTest} from '../src/__stories__';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put it in ../src/__stories, because when i had it in dev/App.js the imports that file has were causing issues with the percy tests. I guess this could go into it's separate file. But yes we can just comment out. Not exactly sure though what's causing the issue.. maybe that we reimport plotly.js in that storybook file, from a different place..


const dataSourceOptions = Object.keys(dataSources).map(name => ({
value: name,
Expand Down
19 changes: 19 additions & 0 deletions dev/dataSources.js
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,25 @@ export default {
],

ints: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
states: [
'AL',
'AK',
'AZ',
'AR',
'CA',
'CO',
'CT',
'DE',
'FL',
'GA',
'HI',
'ID',
'IL',
'IN',
'IA',
'KS',
'KY',
],
'jagged ints': [2, 1, 3, 5, 4, 6],
'toggle ints': [1, -1, 1, -1, 1, -1],
'big ints': [1000, 10100, 10000, 20000, 100000],
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"draft-js-utils": "^1.3.3",
"fast-isnumeric": "^1.1.2",
"immutability-helper": "^3.0.0",
"plotly-icons": "1.3.12",
"plotly.js": "1.48.3",
"plotly-icons": "1.3.13",
"plotly.js": "1.49.5",
"prop-types": "^15.7.2",
"raf": "^3.4.1",
"react-color": "^2.17.0",
Expand Down
21 changes: 21 additions & 0 deletions src/EditorControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
shamefullyDeleteRelatedAnalysisTransforms,
shamefullyAdjustSizeref,
shamefullyAdjustAxisDirection,
shamefullyAdjustMapbox,
} from './shame';
import {EDITOR_ACTIONS} from './lib/constants';
import isNumeric from 'fast-isnumeric';
Expand Down Expand Up @@ -87,6 +88,9 @@ class EditorControls extends Component {
shamefullyAdjustAxisRef(graphDiv, payload);
shamefullyAddTableColumns(graphDiv, payload);
shamefullyAdjustSplitStyleTargetContainers(graphDiv, payload);
if (!this.props.mapBoxAccess) {
shamefullyAdjustMapbox(graphDiv, payload);
}

for (let i = 0; i < payload.traceIndexes.length; i++) {
for (const attr in payload.update) {
Expand Down Expand Up @@ -283,6 +287,19 @@ class EditorControls extends Component {
}
break;

case EDITOR_ACTIONS.DELETE_MAPBOXLAYER:
if (isNumeric(payload.mapboxLayerIndex)) {
graphDiv.layout[payload.mapboxId].layers.splice(payload.mapboxLayerIndex, 1);
if (this.props.onUpdate) {
this.props.onUpdate(
graphDiv.data,
Object.assign({}, graphDiv.layout),
graphDiv._transitionData._frames
);
}
}
break;

case EDITOR_ACTIONS.DELETE_TRANSFORM:
if (isNumeric(payload.transformIndex) && payload.traceIndex < graphDiv.data.length) {
if (graphDiv.data[payload.traceIndex].transforms.length === 1) {
Expand Down Expand Up @@ -327,6 +344,10 @@ class EditorControls extends Component {
move(graphDiv.layout.annotations);
}

if (payload.path === 'layout.mapbox.layers') {
move(graphDiv.layout[payload.mapboxId].layers);
}

const updatedData = payload.path.startsWith('data')
? graphDiv.data.slice()
: graphDiv.data;
Expand Down
73 changes: 73 additions & 0 deletions src/components/containers/MapboxLayersAccordion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import PlotlyFold from './PlotlyFold';
import PlotlyPanel from './PlotlyPanel';
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {connectLayersToMapbox, getParsedTemplateString} from 'lib';

const MapboxLayersFold = connectLayersToMapbox(PlotlyFold);

class MapboxLayersAccordion extends Component {
render() {
const {
fullContainer: {layers = []},
localize: _,
layout: meta,
} = this.context;
const {children} = this.props;

const content =
layers.length &&
layers.map((layer, i) => (
<MapboxLayersFold
key={i}
mapboxLayerIndex={i}
name={getParsedTemplateString(layer.name, {meta})}
canDelete={true}
>
{children}
</MapboxLayersFold>
));

const addAction = {
label: _('Layer'),
handler: context => {
const {fullContainer, updateContainer} = context;
if (updateContainer) {
const mapboxLayerIndex = Array.isArray(fullContainer.layers)
? fullContainer.layers.length
: 0;

updateContainer({
[`layers[${mapboxLayerIndex}]`]: {
name: `Layer ${mapboxLayerIndex}`,
sourcetype: 'raster',
below: 'traces',
},
});
}
},
};

return (
<PlotlyPanel addAction={addAction} canReorder>
{content ? content : null}
</PlotlyPanel>
);
}
}

MapboxLayersAccordion.contextTypes = {
fullContainer: PropTypes.object,
localize: PropTypes.func,
layout: PropTypes.object,
};

MapboxLayersAccordion.propTypes = {
children: PropTypes.node,
};

MapboxLayersAccordion.plotly_editor_traits = {
no_visibility_forcing: true,
};

export default MapboxLayersAccordion;
2 changes: 2 additions & 0 deletions src/components/containers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SliderAccordion from './SliderAccordion';
import ImageAccordion from './ImageAccordion';
import UpdateMenuAccordion from './UpdateMenuAccordion';
import RangeSelectorAccordion from './RangeSelectorAccordion';
import MapboxLayersAccordion from './MapboxLayersAccordion';
import AxesFold from './AxesFold';
import PlotlyFold, {Fold} from './PlotlyFold';
import MenuPanel from './MenuPanel';
Expand All @@ -27,6 +28,7 @@ export {
ImageAccordion,
UpdateMenuAccordion,
RangeSelectorAccordion,
MapboxLayersAccordion,
MenuPanel,
PlotlyFold,
Fold,
Expand Down
8 changes: 7 additions & 1 deletion src/components/fields/Dropzone.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ UnconnectedDropzone.propTypes = {

UnconnectedDropzone.displayName = 'UnconnectedDropzone';

export default connectToContainer(UnconnectedDropzone);
function modifyPlotProps(props, context, plotProps) {
if (context.container.type === 'choroplethmapbox') {
plotProps.isVisible = true;
}
}

export default connectToContainer(UnconnectedDropzone, {modifyPlotProps});
55 changes: 30 additions & 25 deletions src/components/fields/LocationSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,36 @@ class UnconnectedLocationSelector extends Component {
container: {type: type},
} = this.context;

return type === 'scattergeo' ? (
<>
<Field {...this.props} attr={this.props.attr}>
<Radio
options={[
{value: 'latlon', label: _('Lat/Lon')},
{value: 'location', label: _('Location')},
]}
fullValue={mode}
updatePlot={this.setMode}
attr={this.props.attr}
/>
</Field>
{mode === 'latlon' ? (
<>
<DataSelector label={_('Latitude')} attr="lat" />
<DataSelector label={_('Longitude')} attr="lon" />
</>
) : (
<Location attr="type" />
)}
</>
) : type === 'choropleth' ? (
<Location attr="type" />
) : (
if (type === 'scattergeo') {
return (
<>
<Field {...this.props} attr={this.props.attr}>
<Radio
options={[
{value: 'latlon', label: _('Lat/Lon')},
{value: 'location', label: _('Location')},
]}
fullValue={mode}
updatePlot={this.setMode}
attr={this.props.attr}
/>
</Field>
{mode === 'latlon' ? (
<>
<DataSelector label={_('Latitude')} attr="lat" />
<DataSelector label={_('Longitude')} attr="lon" />
</>
) : (
<Location attr="type" />
)}
</>
);
} else if (type === 'choropleth') {
return <Location attr="type" />;
} else if (type === 'choroplethmapbox') {
return <DataSelector label={_('Locations')} attr="locations" />;
}
return (
<>
<DataSelector label={_('Latitude')} attr="lat" />
<DataSelector label={_('Longitude')} attr="lon" />
Expand Down
4 changes: 2 additions & 2 deletions src/components/fields/SubplotCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {Component} from 'react';
import Dropdown from './Dropdown';
import Info from './Info';
import PropTypes from 'prop-types';
import {EDITOR_ACTIONS, SUBPLOT_TO_ATTR} from 'lib/constants';
import {EDITOR_ACTIONS, SUBPLOT_TO_ATTR, subplotName} from 'lib/constants';
import Button from '../widgets/Button';
import {PlusIcon} from 'plotly-icons';
import {connectToContainer, traceTypeToAxisType, getSubplotTitle} from 'lib';
Expand Down Expand Up @@ -127,7 +127,7 @@ class UnconnectedSubplotCreator extends Component {
<SingleSubplotCreator
attr={SUBPLOT_TO_ATTR[subplotType].data}
layoutAttr={subplotType}
label={SUBPLOT_TO_ATTR[subplotType].layout}
label={subplotName(SUBPLOT_TO_ATTR[subplotType].layout, _)}
options={getOptions(subplotType)}
/>
<Info>
Expand Down
58 changes: 57 additions & 1 deletion src/components/fields/derived.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {UnconnectedColorPicker} from './ColorPicker';
import {UnconnectedTextEditor} from './TextEditor';
import {UnconnectedVisibilitySelect} from './VisibilitySelect';
import {connectToContainer, getAllAxes, getAxisTitle, axisIdToAxisName} from 'lib';
import PropTypes from 'prop-types';
import Text from './Text';

export const AxisAnchorDropdown = connectToContainer(UnconnectedDropdown, {
modifyPlotProps: (props, context, plotProps) => {
Expand Down Expand Up @@ -574,8 +576,14 @@ export const HoverInfo = connectToContainer(UnconnectedFlaglist, {
} else if (container.lat || container.lon) {
options = [{label: _('Longitude'), value: 'lon'}, {label: _('Latitude'), value: 'lat'}];
}
} else if (container.type === 'scattermapbox') {
} else if (container.type === 'scattermapbox' || container.type === 'densitymapbox') {
options = [{label: _('Longitude'), value: 'lon'}, {label: _('Latitude'), value: 'lat'}];
} else if (container.type === 'densitymapbox') {
options = [
{label: _('Longitude'), value: 'lon'},
{label: _('Latitude'), value: 'lat'},
{label: _('Z'), value: 'z'},
];
} else if (container.type === 'scatterternary') {
options = [
{label: _('A'), value: 'a'},
Expand Down Expand Up @@ -655,6 +663,54 @@ export const FillDropdown = connectToContainer(UnconnectedDropdown, {
},
});

export const MapboxSourceArray = connectToContainer(Text, {
modifyPlotProps: (props, context, plotProps) => {
const {fullValue, updatePlot} = plotProps;
if (plotProps.fullValue && plotProps.fullValue.length > 0) {
plotProps.fullValue = fullValue[0];
}

plotProps.updatePlot = v => {
if (v.length) {
updatePlot([v]);
} else {
updatePlot([]);
}
};
},
});

export const MapboxStyleDropdown = connectToContainer(UnconnectedDropdown, {
modifyPlotProps: (props, context, plotProps) => {
const {mapBoxAccess, localize: _} = context;

plotProps.options = (!mapBoxAccess
? []
: [
{label: _('Mapbox Basic'), value: 'basic'},
{label: _('Mapbox Outdoors'), value: 'outdoors'},
{label: _('Mapbox Light'), value: 'light'},
{label: _('Mapbox Dark'), value: 'dark'},
{label: _('Mapbox Satellite'), value: 'satellite'},
{label: _('Mapbox Satellite with Streets'), value: 'satellite-streets'},
]
).concat([
{label: _('No tiles (white background)'), value: 'white-bg'},
{label: _('Open Street Map'), value: 'open-street-map'},
{label: _('Carto Positron'), value: 'carto-positron'},
{label: _('Carto Dark Matter'), value: 'carto-darkmatter'},
{label: _('Stamen Terrain'), value: 'stamen-terrain'},
{label: _('Stamen Toner'), value: 'stamen-toner'},
{label: _('Stamen Watercolor'), value: 'stamen-watercolor'},
]);
plotProps.clearable = false;
},
});
MapboxStyleDropdown.contextTypes = {
mapBoxAccess: PropTypes.bool,
...MapboxStyleDropdown.contextTypes,
};

export const HoveronDropdown = connectToContainer(UnconnectedDropdown, {
modifyPlotProps: (props, context, plotProps) => {
const {localize: _} = context;
Expand Down
Loading