Skip to content

Commit

Permalink
Merge pull request #1597 from pierotofy/multilayer
Browse files Browse the repository at this point in the history
Simultaneous map items display and swipe view
  • Loading branch information
pierotofy authored Feb 8, 2025
2 parents 1bc4ab0 + 50a9dc5 commit beb7ded
Show file tree
Hide file tree
Showing 19 changed files with 659 additions and 55 deletions.
27 changes: 20 additions & 7 deletions app/static/app/js/MapView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ class MapView extends React.Component {

this.state = {
selectedMapType,
tiles: this.getTilesByMapType(selectedMapType)
tiles: this.tilesFromMapType(selectedMapType)
};

this.getTilesByMapType = this.getTilesByMapType.bind(this);
this.tilesFromMapType = this.tilesFromMapType.bind(this);
this.handleMapTypeButton = this.handleMapTypeButton.bind(this);
this.hasTilesOfType = this.hasTilesOfType.bind(this);
}

isThermalMap = () => {
Expand All @@ -75,29 +76,41 @@ class MapView extends React.Component {
return thermalCount === this.props.mapItems.length;
}

getTilesByMapType(type){
tilesFromMapType(type){
// Go through the list of map items and return
// only those that match a particular type (in tile format)
const tiles = [];

this.props.mapItems.forEach(mapItem => {
mapItem.tiles.forEach(tile => {
if (tile.type === type) tiles.push({
tiles.push({
url: tile.url,
meta: mapItem.meta,
type: tile.type
type: tile.type,
selected: tile.type === type
});
});
});

return tiles;
}

hasTilesOfType(type){
for (let i = 0; i < this.props.mapItems.length; i++){
let mapItem = this.props.mapItems[i];
for (let j = 0; j < mapItem.tiles.length; j++){
let tile = mapItem.tiles[j];
if (tile.type === type) return true;
}
}
return false;
}

handleMapTypeButton(type){
return () => {
this.setState({
selectedMapType: type,
tiles: this.getTilesByMapType(type)
tiles: this.tilesFromMapType(type)
});
};
}
Expand Down Expand Up @@ -126,7 +139,7 @@ class MapView extends React.Component {
type: "dtm",
icon: "fa fa-chart-area"
}
].filter(mapType => this.getTilesByMapType(mapType.type).length > 0 );
].filter(mapType => this.hasTilesOfType(mapType.type));

// If we have only one button, hide it...
if (mapTypeButtons.length === 1) mapTypeButtons = [];
Expand Down
4 changes: 3 additions & 1 deletion app/static/app/js/classes/plugins/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export default {
"deleteAnnotation",
"toggleAnnotation",
"annotationDeleted",
"downloadAnnotations"
"downloadAnnotations",
"mapTypeChanged",
"sideBySideChanged",
]
};

2 changes: 1 addition & 1 deletion app/static/app/js/components/LayersControl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default L.Control.extend({
},

update: function(layers, overlays, annotations){
ReactDOM.render(<LayersControlButton map={this.map} layers={layers} overlays={overlays} annotations={annotations} />, this.container);
ReactDOM.render(<LayersControlButton ref={r => this.layersControlButton = r} map={this.map} layers={layers} overlays={overlays} annotations={annotations} />, this.container);
}
});

6 changes: 4 additions & 2 deletions app/static/app/js/components/LayersControlAnnotations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ export default class LayersControlAnnotations extends React.Component {
componentDidUpdate(prevProps, prevState){
if (prevState.visible !== this.state.visible){
this.annRefs.forEach(ann => {
let visible = this.state.visible ? ann.state.visible : false;
PluginsAPI.Map.toggleAnnotation(ann.props.layer, visible);
if (ann){
let visible = this.state.visible ? ann.state.visible : false;
PluginsAPI.Map.toggleAnnotation(ann.props.layer, visible);
}
});
}
}
Expand Down
85 changes: 76 additions & 9 deletions app/static/app/js/components/LayersControlLayer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Utils from '../classes/Utils';
import Workers from '../classes/Workers';
import ErrorMessage from './ErrorMessage';
import ExportAssetPanel from './ExportAssetPanel';
import PluginsAPI from '../classes/plugins/API';
import $ from 'jquery';
import { _, interpolate } from '../classes/gettext';

Expand All @@ -15,20 +16,22 @@ export default class LayersControlLayer extends React.Component {
layer: null,
expanded: false,
map: null,
overlay: false
overlay: false,
separator: false,
};
static propTypes = {
layer: PropTypes.object.isRequired,
expanded: PropTypes.bool,
map: PropTypes.object.isRequired,
overlay: PropTypes.bool
}
overlay: PropTypes.bool,
separator: PropTypes.bool
};

constructor(props){
super(props);

this.map = props.map;

const url = this.getLayerUrl();
const params = Utils.queryParams({search: url.slice(url.indexOf("?"))});

Expand Down Expand Up @@ -63,6 +66,7 @@ export default class LayersControlLayer extends React.Component {
hillshade: params.hillshade || "",
histogramLoading: false,
exportLoading: false,
side: false,
error: ""
};
this.rescale = params.rescale || "";
Expand All @@ -72,14 +76,46 @@ export default class LayersControlLayer extends React.Component {
return this.props.layer._url || "";
}

componentDidMount(){
PluginsAPI.Map.onMapTypeChanged(this.handleMapTypeChange);
PluginsAPI.Map.onSideBySideChanged(this.handleSideBySideChange);
}

handleMapTypeChange = (type, autoExpand) => {
if (this.meta.type !== undefined){
const visible = this.meta.type === type;
const expanded = visible && autoExpand;
this.setState({visible, expanded});
}
}

handleSideBySideChange = (layer, side) => {
// Toggle this layer's side off if it was previously sided
// when another layer is set to side
if (this.props.layer !== layer && this.state.side && side){
setTimeout(() => {
let visible = this.state.visible;
if (this.wasInvisibleOnSideClick){
visible = false;
this.wasInvisibleOnSideClick = false;
}

this.setState({ side: false, visible });
PluginsAPI.Map.sideBySideChanged(this.props.layer, false);
}, 0);
}
}

componentDidUpdate(prevProps, prevState){
const { layer } = this.props;

if (prevState.visible !== this.state.visible){
if (this.state.visible){
layer.addTo(this.map);
if (layer.show) layer.show();
else if (!this.map.hasLayer(layer)) layer.addTo(this.map);
}else{
this.map.removeLayer(layer);
if (layer.hide) layer.hide();
else this.map.removeLayer(layer);
}
}

Expand All @@ -93,7 +129,7 @@ export default class LayersControlLayer extends React.Component {
}

if (prevProps.expanded !== this.props.expanded){
this.state.expanded = this.props.expanded;
this.setState({expanded: this.props.expanded});
}
}

Expand All @@ -107,6 +143,9 @@ export default class LayersControlLayer extends React.Component {
this.exportReq.abort();
this.exportReq = null;
}

PluginsAPI.Map.offSideBySideChanged(this.handleSideBySideChange);
PluginsAPI.Map.offMapTypeChanged(this.handleMapTypeChange);
}

handleZoomToClick = () => {
Expand All @@ -120,6 +159,32 @@ export default class LayersControlLayer extends React.Component {
if (layer.getPopup()) layer.openPopup();
}

handleSideClick = () => {
let { side, visible } = this.state;

if (!side){
side = true;
if (!visible){
visible = true;
this.wasInvisibleOnSideClick = true;
}
}else{
side = false;
if (this.wasInvisibleOnSideClick){
visible = false;
this.wasInvisibleOnSideClick = false;
}
}

this.setState({ side, visible });
PluginsAPI.Map.sideBySideChanged(this.props.layer, side);
}

sideIcon = () => {
if (!this.state.side) return "fa-divide fa-rotate-90";
else return "fa-chevron-right";
}

handleLayerClick = () => {
if (this.props.overlay){
this.setState({visible: !this.state.visible});
Expand Down Expand Up @@ -296,8 +361,8 @@ export default class LayersControlLayer extends React.Component {

return (<div className="layers-control-layer">
<div className="layer-control-title">
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} /> : <div className="paddingSpace"></div>}<Checkbox bind={[this, 'visible']}/>
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}><i className={"layer-icon " + (meta.icon || "fa fa-vector-square fa-fw")}></i><div className="layer-title">{meta.name}</div></a> <a className="layer-action" href="javascript:void(0)" onClick={this.handleZoomToClick}><i title={_("Zoom To")} className="fa fa-expand"></i></a>
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} className="expand-layer" /> : <div className="paddingSpace"></div>}<Checkbox bind={[this, 'visible']}/>
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}><i className={"layer-icon " + (meta.icon || "fa fa-vector-square fa-fw")}></i><div className="layer-title">{meta.name}</div></a> {meta.raster ? <a className="layer-action" href="javascript:void(0)" onClick={this.handleSideClick}><i title={_("Side By Side")} className={"fa fa-fw " + this.sideIcon()}></i></a> : ""}<a className="layer-action" href="javascript:void(0)" onClick={this.handleZoomToClick}><i title={_("Zoom To")} className="fa fa-expand"></i></a>
</div>

{this.state.expanded ?
Expand Down Expand Up @@ -370,6 +435,8 @@ export default class LayersControlLayer extends React.Component {
asset={this.asset}
exportParams={this.getLayerParams}
dropUp />

{this.props.separator ? <hr className="layer-separator" /> : ""}
</div> : ""}
</div>);

Expand Down
12 changes: 9 additions & 3 deletions app/static/app/js/components/LayersControlPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class LayersControlPanel extends React.Component {
this.props.overlays.forEach(scanGroup('overlays'));
this.props.layers.forEach(scanGroup('layers'));
this.props.annotations.forEach(scanGroup('annotations'));

const getGroupContent = group => {
return (<div>

Expand All @@ -83,8 +83,14 @@ export default class LayersControlPanel extends React.Component {
{group.layers.sort((a, b) => {
const m_a = a[Symbol.for("meta")] || {};
const m_b = b[Symbol.for("meta")] || {};
return m_a.name > m_b.name ? -1 : 1;
}).map((layer, i) => <LayersControlLayer map={this.props.map} expanded={this.props.layers.length === 1} overlay={false} layer={layer} key={i} />)}
return m_a.type > m_b.type ? -1 : 1;
}).map((layer, i) => <LayersControlLayer map={this.props.map}
expanded={(layer[Symbol.for("meta")] || {}).autoExpand || false}
overlay={false}
layer={layer}
key={`${i}-${(layer[Symbol.for("meta")] || {}).type}`}
separator={i < group.layers.length - 1}
/>)}
</div>);
};

Expand Down
Loading

0 comments on commit beb7ded

Please sign in to comment.