Skip to content
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
10 changes: 10 additions & 0 deletions src/util.ts
Copy link
Author

@jwardbond jwardbond Dec 4, 2025

Choose a reason for hiding this comment

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

initially wrote an isMapView() check, as suggested #1052 (comment) but turns out view was always "undefined" when I created my maps with m = viz([])

Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ export function sanitizeViewState(
maxZoom: viewState.maxZoom,
}
: 0),
...(Number.isFinite(viewState.pitch)
? {
pitch: viewState.pitch,
}
: 0),
...(Number.isFinite(viewState.bearing)
? {
bearing: viewState.bearing,
}
: 0),
};
return sanitized;
}
10 changes: 8 additions & 2 deletions tests/test_map.py
Copy link
Author

Choose a reason for hiding this comment

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

I don't know the peculiarities of jupyter widgets, but these tests always passed, even with pitch and bearing specified.

Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,20 @@ def test_view_state_orthographic_view_empty():

def test_set_view_state_map_view_kwargs():
m = Map([])
set_state = {"longitude": -100, "latitude": 40, "zoom": 5}
set_state = {
"longitude": -100,
"latitude": 40,
"zoom": 5,
"pitch": 30,
"bearing": 45,
}
m.set_view_state(**set_state)
assert m.view_state == MapViewState(**set_state)


def test_set_view_state_map_view_instance():
m = Map([])
set_state = MapViewState(longitude=-100, latitude=40, zoom=5)
set_state = MapViewState(longitude=-100, latitude=40, zoom=5, pitch=30, bearing=45)
m.set_view_state(set_state)
assert m.view_state == set_state

Expand Down
93 changes: 93 additions & 0 deletions tests/ui/test_mapview_interaction.py
Copy link
Author

Choose a reason for hiding this comment

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

I added some tests. This was fun to play around with.

Oddly, updating pitch/bearing with set_view_state and then calling view_state in the same cell correctly reflected the changes (in the text output, not on the map) but if view_state was instead called in a subsequent cell, pitch and bearing were not updated. This is my best attempt at testing that behavior, and the manual pitch/bearing adjustment behaviour.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Mapview interaction tests."""

import pytest
from IPython.display import display

from lonboard import Map
from lonboard.view_state import MapViewState


@pytest.fixture
def sample_map():
"""Lonboard map for testing."""
return Map([])


def click_and_drag_canvas(
page_session,
start_pos,
end_pos,
button,
):
"""Simulate click and drag on the map.

Start and end positions are 0-100 percentages of the canvas size.
"""
canvas = page_session.locator("canvas").first
canvas.wait_for(state="visible", timeout=5000)
bbox = canvas.bounding_box()

# Convert relative coords to absolute pixels
start_x = bbox["x"] + (start_pos["x"] / 100) * bbox["width"]
start_y = bbox["y"] + (start_pos["y"] / 100) * bbox["height"]
end_x = bbox["x"] + (end_pos["x"] / 100) * bbox["width"]
end_y = bbox["y"] + (end_pos["y"] / 100) * bbox["height"]

page_session.mouse.move(start_x, start_y)
page_session.mouse.down(button=button)
page_session.mouse.move(end_x, end_y)
page_session.mouse.up(button=button)
page_session.wait_for_timeout(500)


@pytest.mark.usefixtures("solara_test")
def test_jupyter_set_view_state(page_session, sample_map):
"""Test setting view state in Jupyter environment."""
m = sample_map
set_state = {
"longitude": -100,
"latitude": 40,
"zoom": 5,
"pitch": 30,
"bearing": 45,
}
m.set_view_state(**set_state)

# Simulate a cell break in Jupyter, best I could do
display(m)
canvas = page_session.locator("canvas").first
canvas.wait_for(timeout=5000)
page_session.wait_for_timeout(1000)

assert m.view_state == MapViewState(**set_state)


@pytest.mark.usefixtures("solara_test")
def test_jupyter_manual_view_state_change(page_session, sample_map):
"""Test manual view state change in Jupyter environment."""
m = sample_map
m.set_view_state(zoom=3)
display(m)
initial_view_state = m.view_state
start_pos = {"x": 50, "y": 50}

# Increase lon from 0 by dragging left
end_pos = {"x": 40, "y": 50}
click_and_drag_canvas(page_session, start_pos, end_pos, button="left")
assert m.view_state.longitude > initial_view_state.longitude

# Increse lat from 0 by dragging down
end_pos = {"x": 50, "y": 60}
click_and_drag_canvas(page_session, start_pos, end_pos, button="left")
assert m.view_state.latitude > initial_view_state.latitude

# Increase pitch by dragging up w. RMB
end_pos = {"x": 50, "y": 40}
click_and_drag_canvas(page_session, start_pos, end_pos, button="right")
assert m.view_state.pitch > initial_view_state.pitch

# Increase bearing by dragging left w. RMB
start_pos = {"x": 40, "y": 40}
end_pos = {"x": 30, "y": 40}
click_and_drag_canvas(page_session, start_pos, end_pos, button="right")
assert m.view_state.bearing > initial_view_state.bearing