From 7537fb098633605ff63ca6e2823da0babd4ef7ef Mon Sep 17 00:00:00 2001 From: danzel Date: Wed, 25 Jul 2012 14:03:23 +1200 Subject: [PATCH] Replace setTimeout(..., 0) calls with explicit forceLayout calls, tidier code. --- src/MarkerCluster.Spiderfier.js | 128 ++++++++++++++++---------------- src/MarkerClusterGroup.js | 79 +++++++++++--------- 2 files changed, 105 insertions(+), 102 deletions(-) diff --git a/src/MarkerCluster.Spiderfier.js b/src/MarkerCluster.Spiderfier.js index 7ed480061d..d993ff386b 100644 --- a/src/MarkerCluster.Spiderfier.js +++ b/src/MarkerCluster.Spiderfier.js @@ -143,78 +143,76 @@ L.MarkerCluster.include(!L.DomUtil.TRANSITION ? { L.FeatureGroup.prototype.addLayer.call(group, m); } - setTimeout(function () { - group._animationStart(); + this._group._forceLayout(); + group._animationStart(); - var initialLegOpacity = L.Browser.svg ? 0 : 0.3, - xmlns = L.Path.SVG_NS; + var initialLegOpacity = L.Browser.svg ? 0 : 0.3, + xmlns = L.Path.SVG_NS; + for (i = childMarkers.length - 1; i >= 0; i--) { + m = childMarkers[i]; + + m.setLatLng(map.layerPointToLatLng(positions[i])); + m.setOpacity(1); + //Add Legs. TODO: Fade this in! + + leg = new L.Polyline([me._latlng, m._latlng], { weight: 1.5, color: '#222', opacity: initialLegOpacity }); + map.addLayer(leg); + m._spiderLeg = leg; + + //Following animations don't work for canvas + if (!L.Browser.svg) { + continue; + } + + //How this works: + //http://stackoverflow.com/questions/5924238/how-do-you-animate-an-svg-path-in-ios + //http://dev.opera.com/articles/view/advanced-svg-animation-techniques/ + + //Animate length + var length = leg._path.getTotalLength(); + leg._path.setAttribute("stroke-dasharray", length + "," + length); + + var anim = document.createElementNS(xmlns, "animate"); + anim.setAttribute("attributeName", "stroke-dashoffset"); + anim.setAttribute("begin", "indefinite"); + anim.setAttribute("from", length); + anim.setAttribute("to", 0); + anim.setAttribute("dur", 0.25); + leg._path.appendChild(anim); + anim.beginElement(); + + //Animate opacity + anim = document.createElementNS(xmlns, "animate"); + anim.setAttribute("attributeName", "stroke-opacity"); + anim.setAttribute("attributeName", "stroke-opacity"); + anim.setAttribute("begin", "indefinite"); + anim.setAttribute("from", 0); + anim.setAttribute("to", 0.5); + anim.setAttribute("dur", 0.25); + leg._path.appendChild(anim); + anim.beginElement(); + } + me.setOpacity(0.3); + + //Set the opacity of the spiderLegs back to their correct value + // The animations above override this until they complete. + // If the initial opacity of the spiderlegs isn't 0 then they appear before the animation starts. + if (L.Browser.svg) { + this._group._forceLayout(); + for (i = childMarkers.length - 1; i >= 0; i--) { - m = childMarkers[i]; + m = childMarkers[i]._spiderLeg; - m.setLatLng(map.layerPointToLatLng(positions[i])); - m.setOpacity(1); - //Add Legs. TODO: Fade this in! - - leg = new L.Polyline([me._latlng, m._latlng], { weight: 1.5, color: '#222', opacity: initialLegOpacity }); - map.addLayer(leg); - m._spiderLeg = leg; - - //Following animations don't work for canvas - if (!L.Browser.svg) { - continue; - } - - //How this works: - //http://stackoverflow.com/questions/5924238/how-do-you-animate-an-svg-path-in-ios - //http://dev.opera.com/articles/view/advanced-svg-animation-techniques/ - - //Animate length - var length = leg._path.getTotalLength(); - leg._path.setAttribute("stroke-dasharray", length + "," + length); - - var anim = document.createElementNS(xmlns, "animate"); - anim.setAttribute("attributeName", "stroke-dashoffset"); - anim.setAttribute("begin", "indefinite"); - anim.setAttribute("from", length); - anim.setAttribute("to", 0); - anim.setAttribute("dur", 0.25); - leg._path.appendChild(anim); - anim.beginElement(); - - //Animate opacity - anim = document.createElementNS(xmlns, "animate"); - anim.setAttribute("attributeName", "stroke-opacity"); - anim.setAttribute("attributeName", "stroke-opacity"); - anim.setAttribute("begin", "indefinite"); - anim.setAttribute("from", 0); - anim.setAttribute("to", 0.5); - anim.setAttribute("dur", 0.25); - leg._path.appendChild(anim); - anim.beginElement(); + m.options.opacity = 0.5; + m._path.setAttribute('stroke-opacity', 0.5); } - me.setOpacity(0.3); + } - //Set the opacity of the spiderLegs back to their correct value - // The animations above override this until they complete. - // Doing this at 250ms causes some minor flickering on FF, so just do it immediately - // If the initial opacity of the spiderlegs isn't 0 then they appear before the animation starts. - if (L.Browser.svg) { - setTimeout(function () { - for (i = childMarkers.length - 1; i >= 0; i--) { - m = childMarkers[i]._spiderLeg; - - m.options.opacity = 0.5; - m._path.setAttribute('stroke-opacity', 0.5); - } - }, 0); - } - - setTimeout(function () { - group._animationEnd(); - }, 250); - }, 0); + setTimeout(function () { + group._animationEnd(); + }, 250); }, _animationUnspiderfy: function () { diff --git a/src/MarkerClusterGroup.js b/src/MarkerClusterGroup.js index 01b1bee4d5..88faebe414 100644 --- a/src/MarkerClusterGroup.js +++ b/src/MarkerClusterGroup.js @@ -305,28 +305,26 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? { }); - //Immediately fire an event to update the opacity and locations (If we immediately set it they won't animate) - setTimeout(function () { - var j, n; + this._forceLayout(); + var j, n; - //Update opacities - me._topClusterLevel._recursivelyBecomeVisible(bounds, depthToStartAt + depthToDescend); - //TODO Maybe? Update markers in _recursivelyBecomeVisible - for (j in me._layers) { - if (me._layers.hasOwnProperty(j)) { - n = me._layers[j]; + //Update opacities + me._topClusterLevel._recursivelyBecomeVisible(bounds, depthToStartAt + depthToDescend); + //TODO Maybe? Update markers in _recursivelyBecomeVisible + for (j in me._layers) { + if (me._layers.hasOwnProperty(j)) { + n = me._layers[j]; - if (!(n instanceof L.MarkerCluster) && n._icon) { - n.setOpacity(1); - } + if (!(n instanceof L.MarkerCluster) && n._icon) { + n.setOpacity(1); } } + } - //update the positions of the just added clusters/markers - me._topClusterLevel._recursively(bounds, depthToStartAt, 0, function (c) { - c._recursivelyRestoreChildPositions(depthToDescend); - }); - }, 0); + //update the positions of the just added clusters/markers + me._topClusterLevel._recursively(bounds, depthToStartAt, 0, function (c) { + c._recursivelyRestoreChildPositions(depthToDescend); + }); this._inZoomAnimation++; @@ -361,10 +359,9 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? { var me = this; - //Immediately fire an event to update the opacity (If we immediately set it they won't animate) - setTimeout(function () { - marker._recursivelyBecomeVisible(bounds, depthToStartAt); - }, 0); + //Update the opacity (If we immediately set it they won't animate) + this._forceLayout(); + marker._recursivelyBecomeVisible(bounds, depthToStartAt); //TODO: Maybe use the transition timing stuff to make this more reliable //When the animations are done, tidy up @@ -383,28 +380,36 @@ L.MarkerClusterGroup.include(!L.DomUtil.TRANSITION ? { if (newCluster !== layer) { if (newCluster._childCount > 2) { //Was already a cluster + this._forceLayout(); this._animationStart(); + + var backupLatlng = layer.getLatLng(); + layer.setLatLng(newCluster._latlng); + layer.setOpacity(0); + setTimeout(function () { + L.FeatureGroup.prototype.removeLayer.call(me, layer); + layer.setLatLng(backupLatlng); - - var backupLatlng = layer.getLatLng(); - layer.setLatLng(newCluster._latlng); - layer.setOpacity(0); - - setTimeout(function () { - L.FeatureGroup.prototype.removeLayer.call(me, layer); - layer.setLatLng(backupLatlng); - - me._animationEnd(); - }, 250); - }, 0); + me._animationEnd(); + }, 250); } else { //Just became a cluster - setTimeout(function () { - me._animationStart(); - me._animationZoomOutSingle(newCluster, 0, 1); - }, 0); + this._forceLayout(); + + me._animationStart(); + me._animationZoomOutSingle(newCluster, 0, 1); } } + }, + + //Force a browser layout of stuff in the map + // Should apply the current opacity and location to all elements so we can update them again for an animation + _forceLayout: function () { + //In my testing this works, infact offsetWidth of any element seems to work. + //Could loop all this._layers and do this for each _icon if it stops working + + L.Util.falseFn(document.body.offsetWidth); + } }); \ No newline at end of file