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

Extract & Restrict Bounds/Zoom #211

Open
zacdav opened this issue Jul 10, 2019 · 22 comments
Open

Extract & Restrict Bounds/Zoom #211

zacdav opened this issue Jul 10, 2019 · 22 comments
Labels
enhancement New feature or request

Comments

@zacdav
Copy link
Contributor

zacdav commented Jul 10, 2019

In leaflet the ability to extract the zoom and bounds of the current map is accessible via
input$<map_id>_zoom and input$<map_id>_bounds, would it be possible to expose these for mapdeck too? Additionally the ability to set the zoom and bounds would be useful.

I've tried to see if there is existing functionality for this - but not entirely sure how easy it is to access.

@zacdav zacdav added the enhancement New feature or request label Jul 10, 2019
@zacdav
Copy link
Contributor Author

zacdav commented Jul 10, 2019

Going through the JS code I seem to be able to do this in the browser console for zoom
window[ 'map' + 'map'].viewState["default-view"].zoom

@zacdav
Copy link
Contributor Author

zacdav commented Jul 11, 2019

Currently am accessing zoom using the following:

JavaScript:

shinyjs.getzoom = function(mapdeck_map) {
  
  let view = window[mapdeck_map + 'map'].viewState['default-view'];
  let zoom = 0;
  
  if (view !== undefined) {
    zoom = view.zoom;
  }
  
  Shiny.onInputChange(mapdeck_map + '_zoom', zoom);
  
};

added to ui.R

# ...
useShinyjs(),
extendShinyjs(script = "jsfuncs.js", functions = "getzoom")
# ...

getting zoom via event

# ...
observeEvent(input$test_zoom, {
        js$getzoom("mapdeck")
        message(input$mapdeck_zoom)
    })
# ...

Problem with this is that an event is required to trigger js$getzoom("mapdeck").
If we just added the js function as a consequence of the map changing it should work without it I think?

SymbolixAU pushed a commit that referenced this issue Jul 11, 2019
@SymbolixAU
Copy link
Collaborator

I think we need to make use of onViewStateChange when setting up the initial Deck object. I've made a commit to branch 'issue211' which you're welcome to install, and you can see the data returned in a shiny session with this small example

library(shiny)
library(shinydashboard)
library(mapdeck)

set_token( "TOKEN" )

ui <- dashboardPage(
	dashboardHeader()
	, dashboardSidebar()
	, dashboardBody(
		mapdeck::mapdeckOutput(
			outputId = "map"
		)
	)
)

server <- function( input, output ) {
	
	output$map <- mapdeck::renderMapdeck({
		mapdeck()
	})
	
	observeEvent({input$map_view_change},{
		print(input$map_view_change)
	})
}

shinyApp(ui, server)

References:

@zacdav
Copy link
Contributor Author

zacdav commented Jul 11, 2019

Seems to be working great so far - just need to find a way to calculate the bounds based from the lat/lon.

Thanks.

@dcooley
Copy link
Collaborator

dcooley commented Jul 11, 2019

yeah I reckon there's probably a way to either calculate that or get it directly from somewhere, but I haven't found the solution yet.

@zacdav
Copy link
Contributor Author

zacdav commented Jul 11, 2019

maybe useful related to settings bounds: visgl/react-map-gl#442

Also I'm digging around for how the mapbox tiles are queried - it seems as if that requires the bounding box to determine the tiles - hopefully will find something there.

@zacdav
Copy link
Contributor Author

zacdav commented Jul 11, 2019

I was able to get kinda close using the following, its not perfect due to assuming spherical earth, but conceptually it seems fine.

Works good enough for my current needs

pixel_to_degrees <- function(x, zoom) {
    # https://wiki.openstreetmap.org/wiki/Zoom_levels
    360 * cos(x) / (2 ^ (zoom + 8)) # degree per pixel
}

get_map_bounds <- function(width, height, origin, zoom) {
    #  width: width of map view in pixels
    # height: height of map view in pixels
    # origin: the centre of the map in degrees (lon, lat)
    #   zoom: zoom of the map (0 - 20)
    dimensions <- pixel_to_degrees(origin, zoom) / 2
    
    bbox <- c(xmin = origin[1] - (dimensions[1] * width),
              ymin = origin[2] - (dimensions[2] * height),
              xmax = origin[1] + (dimensions[1] * width),
              ymax = origin[2] + (dimensions[2] * height))
    
    bbox
    
}

@SymbolixAU
Copy link
Collaborator

asking the source: visgl/deck.gl#3344

@SymbolixAU
Copy link
Collaborator

@zacdav I won't be able to update this for a few days so you're welcome to have a go and submit a PR if you get a good solution working.

@SymbolixAU
Copy link
Collaborator

@zacdav with your updates, have you noticed any performance issues? I'm wondering if constantly creating a new WebMercatorViewport() every time the view changes will take its toll on performance?

@zacdav
Copy link
Contributor Author

zacdav commented Jul 21, 2019

I was wondering the same thing the other day - but I was zooming in and out quite quickly testing it and it seemed fine for me. I will test more at work later with the dashboard I needed this for.
Leaflet has similar behavior and I've not had issues monitoring constantly for zoom or bounds

@zacdav
Copy link
Contributor Author

zacdav commented Jul 22, 2019

Don't seem to notice any performance degradation. Is working great.

dcooley added a commit that referenced this issue Sep 15, 2019
@dcooley
Copy link
Collaborator

dcooley commented Sep 15, 2019

now in master

@dcooley dcooley closed this as completed Sep 15, 2019
@SymbolixAU
Copy link
Collaborator

SymbolixAU commented Sep 20, 2019

Reopening: East & West aren't constrained to -180:180 - visgl/deck.gl#3344 (comment)

@SymbolixAU SymbolixAU reopened this Sep 20, 2019
SymbolixAU pushed a commit that referenced this issue Nov 13, 2019
@SymbolixAU
Copy link
Collaborator

I've added more events, and an interactionState to the view_change event

https://github.com/SymbolixAU/mapdeck/blob/master/inst/htmlwidgets/mapdeck.js#L83

@SymbolixAU
Copy link
Collaborator

related: #237

SymbolixAU pushed a commit that referenced this issue Nov 15, 2019
@SymbolixAU
Copy link
Collaborator

In the absence of a fix in Deckgl for #211 (comment), I've added these conditions

const viewport = new WebMercatorViewport(viewState);
const nw = viewport.unproject([0, 0]);
const se = viewport.unproject([viewport.width, viewport.height]);

const w = nw[0] < -180 ? -180 : ( nw[0] > 180 ? 180 : nw[0] );
const n = nw[1] < -90 ? -90 : ( nw[1] > 90 ? 90 : nw[1] );

const e = se[0] < -180 ? -180 : ( se[0] > 180 ? 180 : se[0] );
const s = se[1] < -90 ? -90 : ( se[1] > 90 ? 90 : se[1] );

viewState.viewBounds = {
  north: n, //nw[1],
  east:  e, //se[0],
  south: s, //se[1],
  west:  w //nw[0]
 };

Which I think are what's needed.

@SymbolixAU
Copy link
Collaborator

SymbolixAU commented Jan 20, 2020

Given the update to v8.0 of deck.gl - #239
And associated breaking changes - in particular visgl/deck.gl#4172

This function will be changing, and so the output returned back to R may change slightly too.

@zacdav
Copy link
Contributor Author

zacdav commented Jan 21, 2020

Let me know if you need any support on this

@SymbolixAU
Copy link
Collaborator

gone back to the source again - visgl/deck.gl#4184

SymbolixAU pushed a commit that referenced this issue Jan 23, 2020
@SymbolixAU
Copy link
Collaborator

I think it's all fine now...

@Robinlovelace
Copy link

Related to #324

@SymbolixAU SymbolixAU removed their assignment Jan 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants