<html>
<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.0/leaflet.css"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.0/leaflet.js"></script>
    <title>smooth zoom demo</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }
    #mapid {
        width: 100vw;
        height: 100vh;
    }
    #info_container{
        position: absolute;
        z-index: 999;
        top: 0;
        left: 50%;
        margin-top: 8px;
        padding: 8px;
        transform: translateX(-50%);
        width: 200px;
        height: 64px;
        background: rgba(0, 0, 0, 0.8);
        color: white;
        text-align: center;
    }
    #info_container span{
        font-size: 24px;
    }
</style>
<body>
<div id="mapid"></div>
<div id="info_container"></div>
<script src="script.js"></script>
<script>
    var mymap = L.map('mapid', {
        scrollWheelZoom: false,
        smoothWheelZoom: true,
        smoothSensitivity: 1,
    }).setView([38.0, 140.0], 13);
    mymap.scrollWheelZoom = true;
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(mymap);
    mymap.on("zoom", function() {
        showZoom();
    })
    function showZoom() {
        document.getElementById('info_container').innerHTML = "zoom<br/>" + "<span>" + mymap.getZoom().toFixed(2) + "</span>";
    }
    showZoom();
</script>
</body>
</html>




L.Map.mergeOptions({
    smoothWheelZoom: true,
    smoothSensitivity: 1
});
L.Map.SmoothWheelZoom = L.Handler.extend({
    addHooks: function() {
        L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
    },
    removeHooks: function() {
        L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll, this);
    },
    _onWheelScroll: function(e) {
        if (!this._isWheeling)
        {
            this._onWheelStart(e);
        }
        this._onWheeling(e);
    },
    _onWheelStart: function(e) {
        var map = this._map;
        this._isWheeling = true;
        this._wheelMousePosition = map.mouseEventToContainerPoint(e);
        this._centerPoint = map.getSize()._divideBy(2);
        this._startLatLng = map.containerPointToLatLng(this._centerPoint);
        this._wheelStartLatLng = map.containerPointToLatLng(this._wheelMousePosition);
        this._startZoom = map.getZoom();
        this._moved = false;
        this._zooming = true;
        map._stop();
        if (map._panAnim) map._panAnim.stop();
        this._goalZoom = map.getZoom();
        this._prevCenter = map.getCenter();
        this._prevZoom = map.getZoom();
        this._zoomAnimationId = requestAnimationFrame(this._updateWheelZoom.bind(this));
    },
    _onWheeling: function(e) {
        var map = this._map;
        this._goalZoom = this._goalZoom - e.deltaY * 0.003 * map.options.smoothSensitivity;
        if (this._goalZoom < map.getMinZoom() || this._goalZoom > map.getMaxZoom()) 
        {
            this._goalZoom = map._limitZoom(this._goalZoom);
        }
        this._wheelMousePosition = this._map.mouseEventToContainerPoint(e);
        clearTimeout(this._timeoutId);
        this._timeoutId = setTimeout(this._onWheelEnd.bind(this), 200);
    },
    _onWheelEnd: function(e) {
        this._isWheeling = false;
        cancelAnimationFrame(this._zoomAnimationId);
    },
    _updateWheelZoom: function() {
        var map = this._map;
        if ((!map.getCenter().equals(this._prevCenter)) || map.getZoom() != this._prevZoom) return;
        this._zoom = map.getZoom() + (this._goalZoom - map.getZoom()) * 0.3;
        this._zoom = Math.floor(this._zoom * 100) / 100;
        var delta = this._wheelMousePosition.subtract(this._centerPoint);
        if (delta.x === 0 && delta.y === 0) return;
        if (map.options.smoothWheelZoom === 'center')
        {
            this._center = this._startLatLng;
        }
        else
        {
            this._center = map.unproject(map.project(this._wheelStartLatLng, this._zoom).subtract(delta), this._zoom);
        }
        if (!this._moved) 
        {
            map._moveStart(true, false);
            this._moved = true;
        }
        map._move(this._center, this._zoom);
        this._prevCenter = map.getCenter();
        this._prevZoom = map.getZoom();
        this._zoomAnimationId = requestAnimationFrame(this._updateWheelZoom.bind(this));
    }
});
L.Map.addInitHook('addHandler', 'smoothWheelZoom', L.Map.SmoothWheelZoom);



/* Styles go here */