Skip to content
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

Feature/slider control #78

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
37 changes: 26 additions & 11 deletions _experimental/layer_switcher_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
import webbrowser

from maplibre import Map, MapOptions, render_maplibregl
from maplibre import Layer, LayerType, Map, MapOptions, render_maplibregl
from maplibre.basemaps import Carto
from maplibre.controls import (
ControlPosition,
Expand All @@ -12,6 +12,7 @@
NavigationControl,
ScaleControl,
)
from maplibre.sources import GeoJSONSource
from shiny.express import input, render, ui

m = Map(
Expand All @@ -23,23 +24,37 @@
pitch=40,
)
)
layer_id = "this-is-a-very-log-id-for-my-awesome-layer"
m.add_layer(
Layer(
type=LayerType.LINE,
id=layer_id,
source=GeoJSONSource(
data="https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/bart.geo.json"
),
paint={"line-width": 4, "line-color": "red", "line-opacity": 0.55},
)
)
m.add_control(NavigationControl())
m.add_control(ScaleControl(), ControlPosition.BOTTOM_LEFT)

# m.add_call(
# "addControl",
# "InfoBoxControl",
# {
# "cssText": "padding: 20px; font-size: 20px;font-family: monospace;",
# "content": "<h1>Awesome control.</h1><p>And some text.</p>",
# },
# ControlPosition.TOP_LEFT.value,
# )
m.add_call(
"addControl",
"LayerOpacityControl",
{
"layerIds": ["water", layer_id],
"toggleLayers": True,
"flexDirection": None,
# "cssText": "padding: 20px; font-size: 20px;font-family: monospace;",
# "content": "<h1>Awesome control.</h1><p>And some text.</p>",
},
ControlPosition.TOP_LEFT.value,
)

m.add_control(InfoBoxControl(content="Toggle layers"), ControlPosition.TOP_LEFT)
m.add_control(
LayerSwitcherControl(
layer_ids=["water", "landcover"],
layer_ids=["water", layer_id],
theme="default",
# css_text="padding: 10px; border: 1px solid black; border-radius: 3x;font-size: 15px;",
),
Expand Down
2 changes: 1 addition & 1 deletion maplibre/srcjs/pywidget.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions maplibre/srcjs/pywidget.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions srcjs/css/custom-opacity-control.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.layer-opacity-ctrl #menu {
display: flex;
flex-direction: column;
align-items: center;
border-bottom: 1px solid black;
padding-bottom: 10px;
}

.layer-opacity-ctrl a {
background-color: #ffffff;
color: darkgrey;
border: 0;
text-decoration: none;
text-align: center;
}
85 changes: 85 additions & 0 deletions srcjs/custom-controls/layer-opacity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { createToggleLayerLink } from "../utils";

import "../css/custom-opacity-control.css";

function createLabel(layerId) {
const label = document.createElement("span");
label.innerHTML = layerId;
return label;
}

function getOpacityPropName(map, layerId) {
const layer = map.getLayer(layerId);
return `${layer.type}-opacity`;
}

function createSlider(
map,
layerId,
toggleLayers = false,
flexDirection = "column",
) {
const label = toggleLayers
? createToggleLayerLink(map, layerId)
: createLabel(layerId);
const slider = document.createElement("input");
slider.type = "range";
slider.min = "0";
slider.max = "1.0";
slider.step = "0.1";

// This might fail if layer is not already added to the map
// TODO: Put it in a try catch statement
const prop = getOpacityPropName(map, layerId);
const currentValue = map.getPaintProperty(layerId, prop) || 1;
console.log("currentValue", currentValue);
slider.value = currentValue;
// -------------------------

slider.style.width = "100px";
slider.oninput = function (e) {
const prop = getOpacityPropName(map, layerId);
const value = parseFloat(this.value);
console.log(prop, value);
map.setPaintProperty(layerId, prop, value);
};
const div = document.createElement("div");
div.id = "menu";
div.style.flexDirection = flexDirection;
if (div.style.flexDirection === "row") {
div.appendChild(slider);
div.appendChild(label);
return div;
}

div.appendChild(label);
div.appendChild(slider);
return div;
}

export default class LayerOpacityControl {
constructor(options) {
this._options = options;
}

onAdd(map) {
this._map = map;
this._container = document.createElement("div");
this._container.className =
"maplibregl-ctrl maplibregl-ctrl-group layer-switcher-ctrl-simple layer-opacity-ctrl";
this._container.style.cssText = this._options.cssText || "padding: 5px;";
const layerIds = this._options.layerIds || [];
const toggleLayers = this._options.toggleLayers || false;
const flexDirection = this._options.flexDirection || "column";
for (const layerId of layerIds) {
const slider = createSlider(map, layerId, toggleLayers, flexDirection);
this._container.appendChild(slider);
}
return this._container;
}

onRemove() {
this._container.parentNode.removeChild(this._container);
this._map = undefined;
}
}
2 changes: 2 additions & 0 deletions srcjs/pymaplibregl.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ maplibregl.addProtocol("pmtiles", protocol.tile);
// Add custom controls
import InfoBoxControl from "./custom-controls/info-box";
import LayerSwitcherControl from "./custom-controls/layer-switcher";
import LayerOpacityControl from "./custom-controls/layer-opacity";
maplibregl.LayerSwitcherControl = LayerSwitcherControl;
maplibregl.InfoBoxControl = InfoBoxControl;
maplibregl.LayerOpacityControl = LayerOpacityControl;

import {
getTextFromFeature,
Expand Down
34 changes: 33 additions & 1 deletion srcjs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,36 @@ function getDeckMapLibrePopupTooltip(map, tooltip) {
};
}

export { getTextFromFeature, getDeckTooltip, getDeckMapLibrePopupTooltip };
// Used in controls
function createToggleLayerLink(map, layerId) {
const link = document.createElement("a");
link.id = layerId;
link.href = "#";
link.textContent = layerId;
const visibility = map.getLayoutProperty(layerId, "visibility");
if (typeof visibility === "undefined" || visibility === "visible") {
link.className = "active";
}

link.onclick = function (e) {
const layerIdClicked = this.textContent;
const visibility = map.getLayoutProperty(layerIdClicked, "visibility");
console.log(layerIdClicked, visibility);
if (typeof visibility === "undefined" || visibility === "visible") {
map.setLayoutProperty(layerIdClicked, "visibility", "none");
this.className = "";
return;
}

map.setLayoutProperty(layerIdClicked, "visibility", "visible");
this.className = "active";
};
return link;
}

export {
getTextFromFeature,
getDeckTooltip,
getDeckMapLibrePopupTooltip,
createToggleLayerLink,
};
Loading