{
const id_mapbox = "map_animacion";
const id_vessel = "vessel_animacion";
let container = html`<div id="${id_mapbox}" style='height:400px; width: 100%; background-color: #f3f3f3' /></div>`;
yield container;
if (show_3) {
play;
let map = new mapboxgl.Map({
container,
center: [-5, 54],
zoom: 6.5,
style: "mapbox://styles/mapbox/light-v9",
scrollZoom: false
});
//// Contenedor CANVAS ////
// 1 - obtén el ancho y el alto del contenedor
const width = d3.select(`#${id_mapbox}`).node().clientWidth;
const height = d3.select(`#${id_mapbox}`).node().clientHeight;
// 2 - añade un nuevo div encima de nuestro mapa mapbox
// lo utilizaremos para modificar el CSS y poner nuestras trayectorias encima
d3.select(`#${id_mapbox}`).append("div").attr("id", "animation");
// 3 - añade nuestro nuevo canvas (que utilizaremos para incluir las trayectorias)
// en este nuevo div
const canvas = d3
.select("#animation")
.append("canvas")
.attr("id", id_vessel)
.node();
//// Atributos de canvas ////
// escálalo al doble de su tamaño para que tenga una buena resolución
// esta escala sólo se hace al principio!
canvas.width = 2 * width;
canvas.height = 2 * height;
//// Atributos de contexto --- como queremos pintar? ////
// èste es el sistema habitual para pintar en canvas
const ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = "normal";
ctx.imageSmoothingEnabled = false;
ctx.globalAlpha = 1;
ctx.scale(2, 2); // nuestras escalas tienen que ser las mismas
ctx.clearRect(0, 0, width, height); // igual que mapbox
ctx.linecap = "round";
ctx.linejoin = "round";
// objetos para controlar la animación
let t = t_extent[0];
// const speed = 1000 * 60 * 5; // 5 min
const speed = speed_2;
//// Funciones para dibujar las líneas ////
// crea una proyección para transformar los `lon` y `lat` a los pixeles de mapbox
function projection(lonlat) {
const p = map.project(new mapboxgl.LngLat(lonlat[0], lonlat[1]));
return [p.x, p.y];
}
// tenemos que saber como dibujar la trayectoria
// para lo cual utilizaremos
// d3.line()
// con la proyección de mapbox que hemos creado `proyection`
// por último, indicaremos que vamos a dibujar en nuestro canvas no en SVG
const pathLine = d3
.line()
.x((d) => projection([d.lon, d.lat])[0])
.y((d) => projection([d.lon, d.lat])[1])
.context(ctx);
draw();
// Pintemos
// Guarda tu forma de pintar en una función para que sea fácil
// reutilizarla después
function draw() {
// limpia el fondo de tu canvas -- borra cualquier cosa que tengas
ctx.globalCompositeOperation = "normal";
ctx.fillStyle = "white";
ctx.globalAlpha = 1;
ctx.fillRect(0, 0, width, height);
//// datos del barco ////
// toda la trayectoria pasada
const past = vessel.filter((d) => parseDate(d.timestamp) <= t);
// la trayectoria pasada más cercana al momento actual
// coge los últimos 100 minutos
const current = vessel.filter(
(d) =>
parseDate(d.timestamp) <= t + hour &&
parseDate(d.timestamp) > t - hour
);
//// dibujemos ////
// trayectoria anterior
ctx.strokeStyle = color;
ctx.fillStyle = "none";
ctx.globalAlpha = 0.3;
ctx.lineWidth = 1;
ctx.beginPath();
pathLine(past);
ctx.stroke();
// trayectoria actual
ctx.globalAlpha = 0.6;
ctx.lineWidth = 2;
ctx.beginPath();
pathLine(current);
ctx.stroke();
// barco - última posición
if (current.length > 0) {
var xy = projection([
current[current.length - 1].lon,
current[current.length - 1].lat
]);
ctx.fillStyle = color;
ctx.strokeStyle = color_2;
ctx.globalAlpha = 1;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(xy[0], xy[1], 4, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
// actualiza valores de animación
// se utilizarán para filtrar los datos
// y parar la animación
if (t < t_extent[1]) {
t = t + speed;
window.requestAnimationFrame(draw);
} else if (t >= t_extent[1]) {
t = t_extent[1];
}
}
// Be careful to clean up the map's resources using \`map.remove()\` whenever
// this cell is re-evaluated.
invalidation.then(() => map.remove());
}
}