Zoom animé : tuiles scalées d'un bloc comme le fond de carte
Les marqueurs Leaflet glissent pendant l'animation de zoom sans changer de taille : les tuiles LiDAR nageaient sur le fond OSM puis sautaient à la fin du zoom. Elles vivent désormais dans un pane dédié (lidarTiles) qui reçoit la même mise à l'échelle que les couches de dalles (translate + scale au zoomanim, transition CSS partagée leaflet-zoom-animated) ; markerZoomAnimation est désactivé pour éviter le double mouvement.
This commit is contained in:
@ -1633,9 +1633,10 @@ input[type="range"]::-moz-range-thumb {
|
||||
/* Layout et peinture des tuiles hors écran skippés par le navigateur */
|
||||
content-visibility: auto;
|
||||
}
|
||||
/* Uniquement pendant l'animation de zoom (classe posée par app.js) :
|
||||
scaling sur le GPU, puis libération pour ne pas immobiliser de mémoire. */
|
||||
body.zooming .ltile { will-change: transform; }
|
||||
/* Uniquement pendant l'animation de zoom (classe posée par app.js) : le pane
|
||||
des tuiles porte le scaling — promotion GPU de lui seul (et non des ~1000
|
||||
div de tuiles), puis libération pour ne pas immobiliser de mémoire. */
|
||||
body.zooming .leaflet-lidarTiles-pane { will-change: transform; }
|
||||
.ltile img {
|
||||
position: absolute; inset: 0;
|
||||
width: 100%; height: 100%; object-fit: fill; display: block;
|
||||
@ -1912,10 +1913,23 @@ const map = L.map('viewport', {
|
||||
zoomControl: false,
|
||||
attributionControl: false,
|
||||
minZoom: 4,
|
||||
maxZoom: 19
|
||||
maxZoom: 19,
|
||||
// Les marqueurs ne doivent pas glisser individuellement pendant le zoom :
|
||||
// le pane lidarTiles est mis à l'échelle d'un bloc (voir zoomanim ci-dessous),
|
||||
// le glissement propre des icônes s'ajouterait au scaling (double mouvement).
|
||||
// Seul effet collatéral : le marqueur GPS saute à la fin d'un zoom.
|
||||
markerZoomAnimation: false
|
||||
});
|
||||
// Pane dédié au dessin de zones : les tuiles LiDAR sont des marqueurs
|
||||
// (pane 600) et les vecteurs par défaut vivent en dessous (pane 400) ;
|
||||
// Pane dédié aux tuiles LiDAR (marqueurs) : pendant l'animation de zoom il
|
||||
// reçoit la même mise à l'échelle que le fond de carte (translate + scale,
|
||||
// transition CSS partagée via la classe leaflet-zoom-animated) — voir le
|
||||
// gestionnaire zoomanim plus bas. La classe .leaflet-zoom-animated fournit
|
||||
// aussi transform-origin: 0 0 (feuille de style Leaflet).
|
||||
const lidarTilesPane = map.createPane('lidarTiles');
|
||||
lidarTilesPane.style.zIndex = 600;
|
||||
lidarTilesPane.classList.add('leaflet-zoom-animated');
|
||||
// Pane dédié au dessin de zones : les tuiles LiDAR vivent en dessous (pane
|
||||
// lidarTiles, 600) et les vecteurs par défaut vivent en dessous (pane 400) ;
|
||||
// on place rectangle et cellules fantômes au-dessus (620), sans capter
|
||||
// les clics (pointer-events: none → la carte reste manipulable).
|
||||
map.createPane('genDraw');
|
||||
@ -2022,7 +2036,8 @@ function registerTile(t) {
|
||||
const mk = L.marker(L.latLng(center[0], center[1]), {
|
||||
icon: icon,
|
||||
interactive: true,
|
||||
keyboard: false
|
||||
keyboard: false,
|
||||
pane: 'lidarTiles'
|
||||
}).addTo(map);
|
||||
mk.on('click', () => {
|
||||
if (exportMode) { toggleExportSel(t); return; }
|
||||
@ -2736,8 +2751,24 @@ gpsBtn.addEventListener('click', () => {
|
||||
}
|
||||
});
|
||||
// will-change pendant l'animation de zoom uniquement : le scaling passe sur
|
||||
// le GPU, et les couches sont libérées juste après (mémoire vidéo).
|
||||
// le GPU, et la couche est libérée juste après (mémoire vidéo).
|
||||
let zoomGpuTimer = null;
|
||||
// Animation de zoom des tuiles calée sur le fond de carte : les marqueurs
|
||||
// Leaflet glissent (transition de position) sans changer de taille — les
|
||||
// tuiles LiDAR « nageaient » donc sur le fond pendant l'animation puis
|
||||
// sautaient à la fin. On applique au pane entier la mise à l'échelle que
|
||||
// Leaflet applique aux couches de dalles : translate + scale autour de
|
||||
// l'origine de la vue cible. La cible coïncide exactement avec la position
|
||||
// que Marker._animateZoom donnerait à chaque icône (project(latlng, z1) −
|
||||
// _getNewPixelOrigin(center, z1)) : le swap à la fin du zoom est sans saut.
|
||||
map.on('zoomanim', (e) => {
|
||||
const s = map.getZoomScale(e.zoom, map.getZoom());
|
||||
const po0 = map.getPixelOrigin();
|
||||
const po1 = map._getNewPixelOrigin(e.center, e.zoom);
|
||||
lidarTilesPane.style.transform =
|
||||
'translate3d(' + (s * po0.x - po1.x) + 'px,' + (s * po0.y - po1.y) + 'px,0) scale(' + s + ')';
|
||||
});
|
||||
map.on('zoomend', () => { lidarTilesPane.style.transform = ''; });
|
||||
map.on('zoomstart', () => {
|
||||
clearTimeout(zoomGpuTimer);
|
||||
document.body.classList.add('zooming');
|
||||
|
||||
Reference in New Issue
Block a user