1

I have a marker (L.divIcon) object in Leaflet. The html content of the marker is an svg. I'm looking to have the divIcon resize when zooming the map.

I've got the necessary code to resize the icons up and down as needed. The issue I'm having is the correct trigger in time. The 'zoomend' event is too late, as by this time the map has already animated. Resizing icons at this stage would have their changes lag behind the map.

map.on('zoomend', function() {
  zoomIcons(currZoom, map.getZoom());
  currZoom = map.getZoom();
});

The 'zoomanim' and 'zoomstart' events don't inform as to the direction of the zoom (in or out) as far as I can tell since map.getZoom() is not updated yet.

Is there another early hook that could be used or some means of determining whether the user is zooming in or out?

For reference below you will find the zoomIcons and dependent functions

/**
 * multiplies CSS values (width, height etc.) preserving their unit
 * @param  {string} cssVal     T css value like -14px or 75%
 * @param  {number} multiplier The multiplication value
 * @return {string}            The css value multipied.
 */
var cssMultiply = function ( cssVal, multiplier ) {
  var returnval = cssVal.substring(0, cssVal.match(/[A-Za-z]/).index) * multiplier
  return returnval + cssVal.substring(cssVal.match(/[A-Za-z]/).index)
}

/**
 * Changes the size of marker icons based on zoom level change
 * @param  {number} oldZoom The previous Leaflet zoom level
 * @param  {number} newZoom The current Leaflet zoom level
 * @return {null}           this function does not return anything
 */
var zoomIcons = function ( oldZoom, newZoom ){

  var zoomRatio = ( newZoom - oldZoom > 0 ) ? 1.5 : 0.666666667;  // 1.25 and 0.8 also works
  var elements = document.getElementsByClassName( 'leaflet-marker-icon' );

  for (var i=0, max=elements.length; i < max; i++) {

    elements[i].style.width      = cssMultiply( elements[i].style.width, zoomRatio );
    elements[i].style.height     = cssMultiply( elements[i].style.height, zoomRatio );
    elements[i].style.marginLeft = cssMultiply( elements[i].style.marginLeft, zoomRatio );
    elements[i].style.marginTop  = cssMultiply( elements[i].style.marginTop, zoomRatio );

  }   
}
  • If zoomstart is too early and zoomend too late, have you tried using zoom? This would be right in between start and end. – BritishSteel Mar 4 '18 at 21:33
4

You mention:

The 'zoomanim' and 'zoomstart' events don't inform as to the direction of the zoom (in or out) as far as I can tell since map.getZoom() is not updated yet.

And that's right, they don't inform because these events are also fired when doing a two-finger pinch-zoom. In this interaction, the user can in fact zoom in and out during that interaction. Think also about a call to flyTo, where the map first zooms out then zooms in, even if the initial and final zoom levels are the same.

The underlying issue here is that a "normal" zoom (when clicking the zoom controls, or using the mouse scrollwheel) relies on CSS transform animations to perform the zoom animation, increasing performance on a lot of situations in browsers that support said CSS transform animations. When a "normal" zoom animation is in progress, there is no javascript running. Therefore, the code cannot fire any events. You can see the actual implementation of the _animateZoom private method of L.Map.

Can this be worked around? Sure.

Just monkey-patch L.Map._animateZoom like so:

var oldAnimateZoom = L.Map.prototype._animateZoom;
L.Map.prototype._animateZoom = function _animateZoom(center, zoom, startAnim, noUpdate) {

     // Add your extra logic here

    oldAnimateZoom(center, zoom, startAnim, noUpdate);
}

Then compare the zoom parameter with the internal this._zoom value before it's updated, and you should be able to get the "direction" of the zooming. On top of that, you'll have to calculate a Bezier curve with unitbezier, as shown here and here, calculate the zoom level form that bezier curve and the time elapsed, and keep doing requestAnimationFrame calls to trigger that calculation until 250msec have passed.

  • Thanks for the pointers. While I can't get to the gitLab repo's you pointed to (private perhaps) I get the gist of it. Thanks. I'll try it that way. Perusing the Leaflet code I also found that I've re-implemented a few things that I could have leveraged the library for. – alfred_j_kwack Mar 6 '18 at 14:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.