Skip to content

Instantly share code, notes, and snippets.

@boromisp
Last active April 1, 2016 21:25
Show Gist options
  • Select an option

  • Save boromisp/bdc8faf182d43bb95d784312a7eff0fc to your computer and use it in GitHub Desktop.

Select an option

Save boromisp/bdc8faf182d43bb95d784312a7eff0fc to your computer and use it in GitHub Desktop.
/* leaflet-react-control: A simple Control for leaflet, that can render React components. */
import { Control, DomUtil } from 'leaflet';
import { render, unmountComponentAtNode } from 'react-dom';
export default Control.extend({
options: { getElement: () => null },
onAdd() {
this.controlDiv = DomUtil.create('div', 'leaflet-control-react');
render(this.options.getElement(), this.controlDiv);
return this.controlDiv;
},
onRemove() {
if (!this.controlDiv) return;
unmountComponentAtNode(this.controlDiv);
this.controlDiv = null;
},
});
/* A [Component -> MapControl] HoC for react-leaflet, that can render any React component as a MapControl. */
import React from 'react';
import { render } from 'react-dom';
import ReactControl from 'leaflet-react-control';
import { MapControl } from 'react-leaflet';
export const ReactMapControl = ControlComponent => class extends MapControl {
static displayName = 'ReactMapControl';
getControlElement = () => {
const { position: _pos, children, ...props } = this.props;
return <ControlComponent {...props}>{children}</ControlComponent>;
};
componentWillMount() {
const { map: _, position, ...props } = this.props;
this.leafletElement = new ReactControl({position, getElement: this.getControlElement});
},
componentDidUpdate(prevProps) {
super.componentDidUpdate(prevProps);
const container = this.leafletElement.controlDiv;
if (container) {
render(this.getControlElement(), container);
}
}
};
/* A basic clone of the L.control.layers for react-leaflet. */
import React, { Component, PropTypes } from 'react';
import { ReactMapControl } from 'react-leaflet-react-map-control';
export default ReactMapControl(LayersControl);
class LayersControl extends Component {
static propTypes = {
baseLayers: PropTypes.object.isRequired,
overlays: PropTypes.object.isRequired,
selectedBaseLayer: PropTypes.string,
selectedOverlays: PropTypes.instanceOf(Set).isRequired,
onBaseLayerSelected: PropTypes.func,
onOverlaysSelected: PropTypes.func,
};
static defaultProps = {
baseLayer: {},
overlays: {},
selectedOverlays: new Set(),
};
state = { expanded: false };
handleMouseOver = () => this.setState({ expanded: true });
handleMouseOut = () => this.setState({ expanded: false });
handleBaseLayerSelected = event => this.props.onBaseLayerSelected(event.target.value);
handleOverlaySelected = event => {
const nextSelected = new Set(this.props.selectedOverlays);
if (event.target.checked) {
nextSelected.add(event.target.value);
} else {
nextSelected.delete(event.target.value);
}
this.props.onOverlaysSelected(nextSelected);
};
render() {
const { expanded } = this.state;
const { baseLayers, overlays, selectedBaseLayer, selectedOverlays } = this.props;
const { handleBaseLayerSelected, handleOverlaySelected, handleMouseOver, handleMouseOut } = this;
const baseLayerIds = Object.keys(baseLayers);
const overlayIds = Object.keys(overlays);
return (
<div className={'leaflet-control-layers leaflet-control' + (expanded ? ' leaflet-control-layers-expanded' : '')} onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
<a class="leaflet-control-layers-toggle" href="#" title="Layers"></a>
<form className='leaflet-control-layers-list'>{baseLayerIds.length > 0 ?
<div className='leaflet-control-layers-base'>{baseLayerIds.map(layerId =>
<label>
<input type='radio' className='leaflet-control-layers-selector' name='leaflet-base-layers' checked={selectedBaseLayer === layerId} value={layerId} onChange={handleBaseLayerSelected} />
<span>{' '}baseLayers[layerId]</span>
</label>)}{baseLayerIds.length && overlayIds.length ?
<div className='leaflet-control-layers-separator' /> : null}
</div> : null}{overlayIds.length > 0 ?
<div className='leaflet-control-layers-overlay'>{overlayIds.map(layerId =>
<label>
<input type='checkbox' className='leaflet-control-layers-selector' checked={selectedOverlays.has(layerId)} value={layerId} onChange={handleOverlaySelected} />
<span>{' '}overlays[layerId]</span>
</label>)}
</div>}
</form>
</div>
);
}
);
class MyMap extends Component {
state = {
selectedBaseLayer: 'tile-layer',
selectedOverlays: new Set('optional-marker-layer'),
};
handleBaseLayerSelected = selectedBaseLayer => this.setState({ selectedBaseLayer });
handleOverlaySelected = selectedOverlays => this.setState({ selectedOverlays });
renderBaseLayer() {
const { selectedBaseLayer } = this.props;
switch (selectedBaseLayer) {
case 'tile-layer':
return <TileLayer url={'https://...'} />;
case 'some-other-layer':
return <OtherBaseLayer ... />;
}
return null;
}
render() {
const { selectedOverlays, selectedBaseLayer } = this.state;
const { renderBaseLayer, handleBaseLayerSelected, handleOverlaySelected } = this;
return (
<Map>
<LayersControl
baseLayers={{
'tile-layer': 'Tile layer label',
'some-other-layer': 'Other layer label'
}}
overlays={{ 'optional-marker-layer': 'Markers...' }}
selectedBaseLayer={selectedBaseLayer}
selectedOverlays={selectedOverlays}
onBaseLayerSelected={handleBaseLayerSelected}
onOverlaysSelected={handleOverlaySelected} />
{renderBaseLayer()}
{selectedOverlays.has('optional-marker-layer') ?
<LayerGroup>
{/* markers... */}
</LayerGroup> : null}
</Map>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment