Skip to content
Snippets Groups Projects
Commit 7bd44c07 authored by pabpart's avatar pabpart
Browse files

Archivo JavaScript

parent cc5646b5
No related branches found
No related tags found
No related merge requests found
const width = document.documentElement.clientWidth;
const height = 0.7 * document.documentElement.clientHeight;
const adj = 0.02 * document.documentElement.clientWidth;
// Fija las dimensiones del gráfico
const svg = d3.select("#grafico").append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "-"
+ adj + " -"
+ adj + " "
+ (width + adj * 3) + " "
+ (height + adj * 3))
const timeConv = d3.timeParse("%Y-%m-%d"); // Esta función proporciona el formato adecuado para leer las fechas del conjunto de datos
const dataset = d3.csv("commodity_futures.csv");
dataset.then(function (data) {
// Establece la primera y última fecha del conjunto de datos como valores predeterminados de las fechas inicial y final
document.getElementById("startDate").setAttribute("min", data[0].Date);
document.getElementById("startDate").setAttribute("value", data[0].Date);
document.getElementById("endDate").setAttribute("max", data[data.length - 1].Date);
document.getElementById("endDate").setAttribute("value", data[data.length - 1].Date);
updateStartDate();
updateEndDate();
drawGraph();
});
// Esta función se ejecuta al principio y cada vez que el usuario modifica la fecha inicial
function updateStartDate() {
// Se actualiza el valor mínimo que se puede seleccionar en la fecha final, para garantizar que la fecha final sea mayor que la inicial.
var start = document.getElementById("startDate").value;
startDate = new Date(start);
var minEndDate = new Date(start);
minEndDate.setDate(minEndDate.getDate() + 1)
document.getElementById("endDate").setAttribute("min", minEndDate.toLocaleDateString("en-CA"));
startDate.setDate(startDate.getDate() - 1);
}
// Esta función se ejecuta al principio y cada vez que el usuario modifica la fecha final
function updateEndDate() {
// Se actualiza el valor máximo que se puede seleccionar en la fecha inicial, para garantizar que la fecha final sea mayor que la inicial.
var end = document.getElementById("endDate").value;
endDate = new Date(end);
var maxStartDate = new Date(end);
maxStartDate.setDate(maxStartDate.getDate() - 1)
document.getElementById("startDate").setAttribute("max", maxStartDate.toLocaleDateString("en-CA"));
}
// Esta función crea el gráfico de líneas. Se ejecuta al principio y cada vez que el usuario pulsa el botón "Aplicar cambios".
function drawGraph() {
d3.selectAll("g").remove(); // Elimina el gráfico anterior
dataset.then(function (data) {
// Selecciona las filas del conjunto de datos que se encuentran en el rango de fechas indicado
var filteredData = data.filter(function (d) { return timeConv(d.Date) >= startDate && timeConv(d.Date) <= endDate });
// Almacena en un array las categorías que el usuario ha seleccionado
var categories = data.columns.slice(2); // La primera columna esta vacía y la segunda corresponde a la variable fecha
var ids = [];
for (i = 0; i < categories.length; i++) {
var c = categories[i];
if (document.getElementById(c).checked) ids.push(c);
}
// Crea un objeto para cada una de las categorías seleccionadas que almacena las fechas y los porcentajes que se van a representar
const slices = ids.map(function (id) {
return {
id: id,
values: filteredData.map(function (d) {
return {
date: timeConv(d.Date),
measurement: (d[id] - filteredData[0][id]) / filteredData[0][id] * 100
};
})
};
});
// Crea las escalas de los ejes
const xScale = d3.scaleTime().range([0, width]);
const yScale = d3.scaleLinear().rangeRound([height, 0]);
// El dominio del eje X es el rango de fechas del conjunto de datos
xScale.domain(d3.extent(filteredData, function (d) {
return timeConv(d.Date)
}));
// El dominio del eje Y está delimitado por el mínimo y el máximo de los porcentajes que se han calculado antes
yScale.domain([
d3.min(slices, function (c) {
return d3.min(c.values, function (d) {
return d.measurement;
});
}),
d3.max(slices, function (c) {
return d3.max(c.values, function (d) {
return d.measurement;
});
})
]);
// Crea los ejes
const yaxis = d3.axisLeft().scale(yScale);
const xaxis = d3.axisBottom().tickFormat(d3.timeFormat("%d/%m/%Y")).scale(xScale);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(xaxis);
// Añade una etiqueta al eje Y
svg.append("g")
.attr("class", "axis")
.call(yaxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("dy", ".75em")
.attr("y", 6)
.style("text-anchor", "end")
.text("Variación (en %)");
// Crea el generador de líneas
const line = d3.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.measurement); });
// Crea una línea para cada categoría
const lines = svg.selectAll("lines")
.data(slices)
.enter()
.append("g");
lines.append("path")
.attr("id", function (d) { return d.id; })
.attr("class", "dataPath")
.attr("d", function (d) { return line(d.values); });
// Esta función toma como argumentos un array ordendado de fechas y una fecha. Devuelve la posición que ocuparía la fecha en el array.
const bisectDate = d3.bisector(function (d) { return d.date; }).left;
// Obtiene el rectángulo que delimita el eje X y crea una nueva escala para el eje X en base a sus dimensiones.
var rectangle = d3.selectAll("path")._groups[0][0].getBoundingClientRect();
var xScaleNew = d3.scaleTime().range([rectangle.left, rectangle.right]);
xScaleNew.domain(d3.extent(filteredData, function (d) {
return timeConv(d.Date)
}));
svg.selectAll(".dataPath")
// Esta función se ejecuta al situar el ratón sobre una línea del gráfico
.on('mouseover', function () {
// Se reduce la opacidad de las demás líneas
d3.selectAll(".dataPath").call(
function (selection) {
selection.attr("opacity", "0.1");
})
d3.select(this).call(
function (selection) {
selection.attr("opacity", "1");
})
// Utiliza la escala creada antes para interpolar la fecha correspondiente a la posición X del ratón
var x0 = xScaleNew.invert(event.pageX);
// Selecciona el identificador (la categoría) del objeto "path" sobre el que se sitúa el ratón
var id = d3.select(this).attr("id");
/* Busca el dato correspondiente a esa categoría cuya fecha está más cerca de la fecha interpolada (hay que tener en cuenta que no se
/* dispone de datos para algunas fechas) */
var columna = slices.find(i => i.id === id);
var i = bisectDate(columna.values, x0);
var d0 = columna.values[i - 1];
var d1 = columna.values[i];
var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
// Si el valor seleccionado es mayor o igual que 0, se le añade un signo +, para representar que se trata de un incremento
var sign = "";
if (Math.sign(d.measurement) >= 0) sign = "+";
// Crea un recuadro en la posición del ratón que muestra la categoría, la fecha seleccionada y el valor correspondiente
tooltip = d3.select("body")
.append("div")
.attr("id", "tooltip")
.html(id.replaceAll(".", " ") + "<br>" + sign + Math.round(d.measurement) + " %<br>" + d.date.toLocaleDateString("es-ES"))
.style("top", event.pageY + "px")
.style("left", event.pageX + "px")
})
// Esta función se ejecuta al mover el ratón sobre una línea del gráfico
.on('mousemove', function () {
// Se actualizan los valores que se muestran en el recuadro de la misma forma que en la función anterior
var x0 = xScaleNew.invert(event.pageX);
var id = d3.select(this).attr("id");
var columna = slices.find(i => i.id === id);
var i = bisectDate(columna.values, x0);
var d0 = columna.values[i - 1];
var d1 = columna.values[i];
var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
var sign = "";
if (Math.sign(d.measurement) >= 0) sign = "+";
tooltip.html(id.replaceAll(".", " ") + "<br>" + sign + Math.round(d.measurement) + " %<br>" + d.date.toLocaleDateString("es-ES"))
.style("top", event.pageY + "px")
.style("left", event.pageX + "px");
})
// Esta función se ejecuta cuando el ratón deja de apuntar a una línea del gráfico
.on('mouseout', function () {
// Todas las líneas vuelven a tener la misma opacidad y desaparece el recuadro
d3.selectAll(".dataPath").call(
function (selection) {
selection.attr("opacity", "1");
})
tooltip.remove();
});
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment