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 */
|
/* Layout et peinture des tuiles hors écran skippés par le navigateur */
|
||||||
content-visibility: auto;
|
content-visibility: auto;
|
||||||
}
|
}
|
||||||
/* Uniquement pendant l'animation de zoom (classe posée par app.js) :
|
/* Uniquement pendant l'animation de zoom (classe posée par app.js) : le pane
|
||||||
scaling sur le GPU, puis libération pour ne pas immobiliser de mémoire. */
|
des tuiles porte le scaling — promotion GPU de lui seul (et non des ~1000
|
||||||
body.zooming .ltile { will-change: transform; }
|
div de tuiles), puis libération pour ne pas immobiliser de mémoire. */
|
||||||
|
body.zooming .leaflet-lidarTiles-pane { will-change: transform; }
|
||||||
.ltile img {
|
.ltile img {
|
||||||
position: absolute; inset: 0;
|
position: absolute; inset: 0;
|
||||||
width: 100%; height: 100%; object-fit: fill; display: block;
|
width: 100%; height: 100%; object-fit: fill; display: block;
|
||||||
@ -1912,10 +1913,23 @@ const map = L.map('viewport', {
|
|||||||
zoomControl: false,
|
zoomControl: false,
|
||||||
attributionControl: false,
|
attributionControl: false,
|
||||||
minZoom: 4,
|
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 dédié aux tuiles LiDAR (marqueurs) : pendant l'animation de zoom il
|
||||||
// (pane 600) et les vecteurs par défaut vivent en dessous (pane 400) ;
|
// 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
|
// on place rectangle et cellules fantômes au-dessus (620), sans capter
|
||||||
// les clics (pointer-events: none → la carte reste manipulable).
|
// les clics (pointer-events: none → la carte reste manipulable).
|
||||||
map.createPane('genDraw');
|
map.createPane('genDraw');
|
||||||
@ -2022,7 +2036,8 @@ function registerTile(t) {
|
|||||||
const mk = L.marker(L.latLng(center[0], center[1]), {
|
const mk = L.marker(L.latLng(center[0], center[1]), {
|
||||||
icon: icon,
|
icon: icon,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
keyboard: false
|
keyboard: false,
|
||||||
|
pane: 'lidarTiles'
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
mk.on('click', () => {
|
mk.on('click', () => {
|
||||||
if (exportMode) { toggleExportSel(t); return; }
|
if (exportMode) { toggleExportSel(t); return; }
|
||||||
@ -2736,8 +2751,24 @@ gpsBtn.addEventListener('click', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// will-change pendant l'animation de zoom uniquement : le scaling passe sur
|
// 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;
|
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', () => {
|
map.on('zoomstart', () => {
|
||||||
clearTimeout(zoomGpuTimer);
|
clearTimeout(zoomGpuTimer);
|
||||||
document.body.classList.add('zooming');
|
document.body.classList.add('zooming');
|
||||||
|
|||||||
Reference in New Issue
Block a user