Skip to content

Commit

Permalink
feat: add a global toolbox in browser (#2160)
Browse files Browse the repository at this point in the history
fix #2097
cf #1500


![image](https://github.com/user-attachments/assets/2c8b96e4-8cf7-4d5f-afed-11adf73e98a8)

This is an alternative proposal for #2097:

- adding the button near the "Filter" toggle was a bit ugly, CSS/HTML
talking, because this "Filters" box is a details/summary
- I thought that other needs could live in the same place: a link to
download the filtered/visible data, and a button to show the map data
extent

The "toggle all" button works this way:
- if one or more layers are shown, it will hide those layers
- otherwise it will show all layers

I've preferred not to change the button icon according to map state,
because I didn't find a reliable way to do so, thus I'm afraid to have
inconsistency, but I can't try harder if needed.

Related: I'm thinking of adding a "Download" button for each layers, as
it's a request that comes quite often.

@Aurelie-Jallut could you have a look ? :)
  • Loading branch information
yohanboniface authored Oct 16, 2024
2 parents 4736490 + 4b66e0f commit ab703e0
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 3 deletions.
46 changes: 46 additions & 0 deletions umap/static/umap/js/modules/browser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from './i18n.js'
import * as Icon from './rendering/icon.js'
import * as Utils from './utils.js'
import { EXPORT_FORMATS } from './formatter.js'
import ContextMenu from './ui/contextmenu.js'

export default class Browser {
constructor(map) {
Expand Down Expand Up @@ -165,6 +168,7 @@ export default class Browser {
})
this.filtersTitle = container.querySelector('summary')
this.toggleBadge()
this.addMainToolbox(container)
this.dataContainer = DomUtil.create('div', '', container)

let fields = [
Expand Down Expand Up @@ -216,6 +220,48 @@ export default class Browser {
}
}

addMainToolbox(container) {
const [toolbox, { toggle, fitBounds, download }] = Utils.loadTemplateWithRefs(`
<div class="main-toolbox">
<i class="icon icon-16 icon-eye" title="${translate('show/hide all layers')}" data-ref="toggle"></i>
<i class="icon icon-16 icon-zoom" title="${translate('zoom to data extent')}" data-ref="fitBounds"></i>
<i class="icon icon-16 icon-download" title="${translate('download visible data')}" data-ref="download"></i>
</div>
`)
container.appendChild(toolbox)
toggle.addEventListener('click', () => this.toggleLayers())
fitBounds.addEventListener('click', () => this.map.fitDataBounds())
download.addEventListener('click', () => this.downloadVisible(download))
}

downloadVisible(element) {
const menu = new ContextMenu({ fixed: true })
const items = []
for (const format of Object.keys(EXPORT_FORMATS)) {
items.push({
label: format,
action: () => this.map.share.download(format),
})
}
menu.openBelow(element, items)
}

toggleLayers() {
// If at least one layer is shown, hide it
// otherwise show all
let allHidden = true
this.map.eachBrowsableDataLayer((datalayer) => {
if (datalayer.isVisible()) allHidden = false
})
this.map.eachBrowsableDataLayer((datalayer) => {
if (allHidden) {
datalayer.show()
} else {
if (datalayer.isVisible()) datalayer.hide()
}
})
}

static backButton(map) {
const button = DomUtil.createButtonIcon(
DomUtil.create('li', '', undefined),
Expand Down
5 changes: 5 additions & 0 deletions umap/static/umap/js/modules/ui/contextmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export default class ContextMenu extends Positioned {
this.openAt([left, top], items)
}

openBelow(element, items) {
const coords = this.getPosition(element)
this.openAt([coords.left, coords.bottom], items)
}

openAt([left, top], items) {
this.container.innerHTML = ''
for (const item of items) {
Expand Down
4 changes: 1 addition & 3 deletions umap/static/umap/js/umap.controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,9 +657,7 @@ const ControlsMixin = {
})
}
button.addEventListener('click', () => {
const x = button.offsetLeft
const y = button.offsetTop + button.offsetHeight
menu.openAt([x, y], actions)
menu.openBelow(button, actions)
})
}
this.help.getStartedLink(rightContainer)
Expand Down
10 changes: 10 additions & 0 deletions umap/static/umap/map.css
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,16 @@ a.umap-control-caption,
.umap-caption .umap-map-author {
padding-inline-start: 31px;
}
.umap-browser .main-toolbox {
padding-left: 4px; /* Align with toolbox below */
border-top: 1px solid var(--color-mediumGray);
margin-top: var(--box-margin);
padding-top: 3px;
padding-bottom: 3px;
}
.umap-browser .main-toolbox i {
cursor: pointer;
}


/* ********************************* */
Expand Down
62 changes: 62 additions & 0 deletions umap/tests/integration/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,65 @@ def test_should_have_edit_buttons_in_edit_mode(live_server, openmap, page, boots
expect(delete_layer).to_be_visible()
expect(edit_feature).to_have_count(3)
expect(delete_feature).to_have_count(3)


def test_main_toolbox_toggle_all_layers(live_server, map, page):
map.settings["properties"]["onLoadPanel"] = "databrowser"
map.save()
data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "one point"},
"geometry": {"type": "Point", "coordinates": [3.33, 46.92]},
},
],
}
DataLayerFactory(map=map, data=data)
data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "one other point"},
"geometry": {"type": "Point", "coordinates": [3.34, 46.94]},
},
],
}
DataLayerFactory(map=map, data=data)
data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "another point"},
"geometry": {"type": "Point", "coordinates": [3.35, 46.95]},
},
],
"_umap_options": {"displayOnLoad": False},
}
DataLayerFactory(map=map, data=data, settings={"displayOnLoad": False})
page.goto(f"{live_server.url}{map.get_absolute_url()}#10/46.93/3.33")
markers = page.locator(".leaflet-marker-icon")
expect(markers).to_have_count(2)
# Only one is off
expect(page.locator(".datalayer.off")).to_have_count(1)

# Click on button
page.locator(".umap-browser [data-ref=toggle]").click()
# Should have hidden the two other layers
expect(page.locator(".datalayer.off")).to_have_count(3)
expect(markers).to_have_count(0)

# Click again
page.locator(".umap-browser [data-ref=toggle]").click()
# Should shown all layers
expect(page.locator(".datalayer.off")).to_have_count(0)
expect(markers).to_have_count(3)

# Click again
page.locator(".umap-browser [data-ref=toggle]").click()
# Should hidden again all layers
expect(page.locator(".datalayer.off")).to_have_count(3)
expect(markers).to_have_count(0)

0 comments on commit ab703e0

Please sign in to comment.