Leaflet / Leaflet

πŸƒ JavaScript library for mobile-friendly interactive maps πŸ‡ΊπŸ‡¦
https://leafletjs.com
BSD 2-Clause "Simplified" License
41.28k stars 5.83k forks source link

Zoom control on map do not work if L_DISABLE_3D = true #6820

Open IMMSPgisgroup opened 5 years ago

IMMSPgisgroup commented 5 years ago

Zoom controls on map do not work if L_DISABLE_3D = true.

<script>L_DISABLE_3D = true;</script>
<script src="leaflet.js"></script>

Sample: https://plnkr.co/edit/S6LVFcI4fsPpSVnP5V5h?p=preview

My LeafletJS version - 1.5.1. OS - Windows 10 Pro 1903 (64-bit). Browser - Mozilla Firefox 69.0.1 (64-bit).


With best regards, IMMSPgisgroup

IvanSanchez commented 5 years ago

Cannot reproduce (using Leaflet 1.5.1 and Firefox 69 on Debian). https://plnkr.co/edit/6SgcGdbjgU3me18QBKhJ?p=preview

IMMSPgisgroup commented 5 years ago

As I see in documentation:

Global switches

Global switches are created for rare cases and generally make Leaflet to not detect a particular browser feature even if it's there. You need to set the switch as a global variable to true before including Leaflet on the page, like this:

<script>L_NO_TOUCH = true;</script>
<script src="leaflet.js"></script>
Switch Description
L_NO_TOUCH Forces Leaflet to not use touch events even if it detects them.
L_DISABLE_3D Forces Leaflet to not use hardware-accelerated CSS 3D transforms for positioning (which may cause glitches in some rare environments) even if they're supported.

But in https://plnkr.co/edit/6SgcGdbjgU3me18QBKhJ?p=preview

<script src="https://unpkg.com/leaflet/dist/leaflet-src.js"></script>
<script>L_DISABLE_3D = true;</script>

Note, that in @IvanSanchez sample L_DISABLE_3D is below LeafletJS loading. For this reason, maybe, bug not reproduced. In addition, I see now if

zoomDelta: 0.25

bug is reproduced. But if zoomDelta not fractional, bug not reproduced. For zoomDelta = 0.5 zoom work, but very strange.


With best regards, IMMSPgisgroup

life777 commented 5 years ago

@IMMSPgisgroup @IvanSanchez

Yes, you are right. The problem is in zoomDelta property. When you try to zoom Leaflet will limit your zoom level. For this reason it calls _limitZoom function here. Inside this function it checks if 3d is turned on or off. If it turned on that Leaflet round new zoom level based on zoomDelta set in map options. If it turned off than Leaflet rounds zoom level to integer.

It means if map has current zoom level 2.0 and user clicks on zoom button in zoom control, _zoomIn function in zoomControl will be called and it adds zoomDelta to the current zoom level here. New zoom level becomes 2.25. But before Leaflet animate zoom change, it calls _limitZoom function that rounds new zoom level to 2.0. It means zoom won't change.

Fix is simple: Use the same code in _zoomIn and _zoomOut function of zoomControl as in zoomIn and zoomOut functions in Map class. There zoomDelta is ignored if 3d is turned off here

delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
johnd0e commented 4 years ago

Perhaps offtopic here, but I've found that L_DISABLE_3D prevents pinch zoom (and make map offsets wrong). Reported here: https://github.com/Leaflet/Leaflet/issues/1759#issuecomment-603777006

albavilanova commented 1 year ago

To add to this topic, zoomSnap doesn't work using L_DISABLE_3D. Reported here: https://github.com/thedirtyfew/dash-leaflet/issues/188

Falke-Design commented 1 year ago

@albavilanova for what reason do you need to set L_DISABLE_3D to true?

albavilanova commented 1 year ago

Hi @Falke-Design, sorry for the delay, I do not know the reason since it was somebody else who set it. However, today I noticed that if I don't include L_DISABLE_3D=true I have problems changing the basemap in our dashboard (I need to zoom to apply the changes).

jonkoops commented 1 year ago

We've removed L_DISABLE_3D for the upcoming v2 of Leaflet, instead opting to always enable 3d acceleration now that it's widely supported by all browsers. If this issue still occurs we should see if we can create a fix for it.

albavilanova commented 1 year ago

Hi @jonkoops, it is good to know that 3d acceleration will be enabled by default, then we are sure that there will be no problems with the zoom snap. I created this piece of code to exemplify what's happening when changing the layers in case you want to test this bug in the upcoming version, you can run the app, remove L_DISABLE_3D and rerun it to see the difference:

import dash
from dash import html
from dash import dcc
import dash_leaflet as dl
from dash.dependencies import Output
from dash.dependencies import Input

leaflet = "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css"
app = dash.Dash(__name__, 
                external_stylesheets=[leaflet])

app.index_string = '''
<!DOCTYPE html>
<html>
    <head>
        <script>
            L_DISABLE_3D=true;
            L_PREFER_CANVAS=true;
            L_SCROLL_WHEEL_ZOOM=false;
        </script>
        {%metas%}
        <title>{%title%}</title>
        {%favicon%}
        {%css%}
    </head>
    <body>
        {%app_entry%}
        <footer>
            {%config%}
            {%scripts%}
            {%renderer%}
        </footer>
    </body>
</html>
'''

zoom_properties = {
    "zoomSnap": 0.1,
    "wheelPxPerZoomLevel": 120,
    "wheelDebounceTime": 80,
    "minZoom": 2
}

map_layers = {"carto-positron": {"name": "Light",
                                 "url": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
                                 "attribution": "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors &copy; <a href='https://carto.com/attributions'>CARTO</a>"
                                },
              "esri-world": {"name": "ESRI",
                             "url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
                             "attribution": "Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
                            }
             }

@dash.callback(
    Output('map', 'children'),
    Input('view-dropdown', 'value')
)
def update_figure(tile_layer):

    print(f'Applying {tile_layer} tile layer')
    fig = dl.Map(dl.TileLayer(
                    url=map_layers[tile_layer]['url'],
                    attribution=map_layers[tile_layer]['attribution']), 
                 style={'width': '100%', 'height': '800px'},
                 zoom=6.2, 
                 center=[40, -3.7], 
                 **zoom_properties)

    return fig

app.layout = html.Div(children=[dcc.Dropdown(
                                    id='view-dropdown',
                                    options=[
                                        {'label': map_layers[style]['name'], 
                                         'value': style}
                                    for style in map_layers],
                                    value='carto-positron',
                                    style={'width': '300px', 'float': 'right', 
                                           'margin-bottom': '10px'}
                                ),
                                html.Div(
                                    id='map'),
                                ])

if __name__ == '__main__':
    app.run_server(debug=True, port=7779)

You will notice that the center of the map changes when switching between layers, zooming in and out gets the map back to its correct position (weirdly).