Commit b34bf9c4 authored by Rodrigo Tapia-McClung's avatar Rodrigo Tapia-McClung

Update to arrow functions

parent 9bd35625
...@@ -101,10 +101,11 @@ const summarizeData = (allData, indicator) => { ...@@ -101,10 +101,11 @@ const summarizeData = (allData, indicator) => {
.rollup( v => { return indicator == "costa" || indicator == "df" ? d3.mean(v, v => v.value) : d3.sum(v, v => v.value) }) .rollup( v => { return indicator == "costa" || indicator == "df" ? d3.mean(v, v => v.value) : d3.sum(v, v => v.value) })
.entries(data2) .entries(data2)
// map "key" and "value" from d3.nest().rollup() to date and value // map "key" and "value" from d3.nest().rollup() to date and value
.map( group => { return { .map( group => {
date: new Date(group.key), return {
value: group.value date: new Date(group.key),
} value: group.value
}
}) })
}); });
// order data[i].values.date // order data[i].values.date
...@@ -112,7 +113,7 @@ const summarizeData = (allData, indicator) => { ...@@ -112,7 +113,7 @@ const summarizeData = (allData, indicator) => {
return data; return data;
} }
function makeIndicatorGraph() { const makeIndicatorGraph = () => {
let data = [], let data = [],
width = 450, width = 450,
...@@ -141,7 +142,7 @@ function makeIndicatorGraph() { ...@@ -141,7 +142,7 @@ function makeIndicatorGraph() {
legendContainer = "legendZone", legendContainer = "legendZone",
updateData; updateData;
function chart(selection) { const chart = selection => {
// get data ranges using values from displayName // get data ranges using values from displayName
minDate = d3.min(data[0].values, d => { minDate = d3.min(data[0].values, d => {
return d[displayName]; return d[displayName];
...@@ -152,7 +153,7 @@ function makeIndicatorGraph() { ...@@ -152,7 +153,7 @@ function makeIndicatorGraph() {
}); });
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
selection.each(function () { selection.each( () => {
// add graph svg to selected container on webpage // add graph svg to selected container on webpage
let areaSVG = selection let areaSVG = selection
...@@ -233,28 +234,178 @@ function makeIndicatorGraph() { ...@@ -233,28 +234,178 @@ function makeIndicatorGraph() {
//console.log("data: ", data.map(d => d.values)); //console.log("data: ", data.map(d => d.values));
let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value));
yLine.domain([0, maxDomain]).nice();
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice();
// add axes
let xaxis = g.select(".x.axis");
xaxis.call(
d3.axisBottom(xLine)
// .ticks(d3.timeMonth.every(1))
// .tickFormat(d3.timeFormat("%b '%y"))
)
.selectAll("text")
//.attr("y", 0)
//.attr("x", 9)
.attr("y", 15)
.attr("x", 0)
.attr("dy", ".35em")
.attr("font-size", "12px")
//.attr("transform", "rotate(90)")
//.style("text-anchor", "start");
.style("text-anchor", "middle")
.style("fill", "#b2b2b2");
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis.selectAll("g.tick line")
.attr("y2", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return -height - 6;
else
return 6;
})
.attr("transform", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "translate(0,6)";
})
.attr("class", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "yearTick";
});
let yaxis = g.select(".y.axis");
yaxis.transition()
.duration(500)
.call(d3.axisLeft(yLine)
/*.tickFormat(d3.format(".2s"))*/
);
// color axis labels
g.selectAll(".y.axis g.tick text")
.style("fill", "#b2b2b2"); // function (d,i) {return (i%2)?"red":"blue";})
let title = selection.select(".title.label");
title.text(chart.title())
.style("fill", "#b2b2b2");
selection.select(".title.label")
.append("tspan")
.attr("class", "far")
.html(" \uf059")
//.style("color", "#b2b2b2")
.style("cursor", "pointer")
.on("click", () => { // when clicking ? display modal with information about indicator
$("#explainIndicatorModal").on("show.bs.modal", () => {
let indicatorName = indicatorsNames[indicators.indexOf(id)]
$("#explainIndicatorModal").find("#explainIndicatorModalTitle").text(indicatorName);
$("#explainIndicatorModal").find(".modal-body").html(indicatorVars[id].explanation);
});
$("#explainIndicatorModal").modal();
});
// update chart
updateData = () => {
let time = map.timeDimension.getCurrentTime();
// update data ranges using values from displayName and lineVariables
minDate = d3.min(data[0].values, d => {
return d[displayName];
});
minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment
maxDate = d3.max(data[0].values, d => {
return d[displayName];
});
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
// update axes' domain
xLine.domain([minDate, maxDate])
//.nice()
//.nice(d3.timeMonth)
.range([0, width - margin.left - margin.right - 30])
.clamp(true);
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; }))
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice()
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value)); let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value));
yLine.domain([0, maxDomain]).nice(); yLine.domain([0, maxDomain])
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice(); //yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice()
.range([height - margin.left - margin.right, 0 + 35])
.nice();
// filter data to only use the ones needed for current time
let filteredData = [];
data.forEach((d, i) => {
filteredData.push({
name: d.name,
values: []
});
d.values.filter(v => {
if (v.date <= new Date(time)) {
filteredData[i].values.push(v);
}
});
});
// update axes
let g = selection.select(".lineChart");
// add axes // update axis line with no ticks
let xaxis = g.select(".x.axis"); let xaxis = g.select(".x.axis");
xaxis.call( xaxis.transition()
.duration(500)
.call(
d3.axisBottom(xLine) d3.axisBottom(xLine)
// .ticks(d3.timeMonth.every(1)) .ticks(0)
// .tickFormat(d3.timeFormat("%b '%y")) .tickSize(0)
);
// update axis ticks - one for each month
let xaxisTicks = g.select(".x.axis-ticks");
let monthsInGraph = [];
userDates.forEach(d => {
monthsInGraph.push(new Date(d));
});
xaxisTicks.transition()
.duration(500)
.call(
d3.axisBottom(xLine)
.tickValues(monthsInGraph)
.tickFormat("")
);
// update axis month labels depending on how many months there are
let xaxisLabels = g.select(".x.axis-month-labels");
// FIXME: check how this displays ticks when there are many months/years
// this fix gives up to 10 ticks
// maybe need to set up more conditions
let numberOfTicks = monthsInGraph.length < 6 ? d3.timeMonth.every(1) : 6;
xaxisLabels.transition().duration(500)
.call(
d3.axisBottom(xLine)
.ticks(numberOfTicks)
.tickFormat(d3.timeFormat("%b"))
) )
.selectAll("text") .selectAll("text")
//.attr("y", 0) .style("fill", "#b2b2b2")
//.attr("x", 9) .attr("font-size", "12px");
.attr("y", 15)
.attr("x", 0) // update axis year labels depending on how many months there are
.attr("dy", ".35em") let xaxisYearLabels = g.select(".x.axis-year-labels");
.attr("font-size", "12px") xaxisYearLabels.transition().duration(500)
//.attr("transform", "rotate(90)") .call(
//.style("text-anchor", "start"); d3.axisBottom(xLine)
.style("text-anchor", "middle") .ticks(numberOfTicks)
.style("fill", "#b2b2b2"); .tickFormat(d3.timeFormat("'%y"))
)
.selectAll("text")
.style("fill", "#b2b2b2")
.attr("font-size", "12px");
// format x-axis lines for minor and major ticks // format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed //TODO: check this line to separate years starting in Jan. Maybe it is not needed
...@@ -278,248 +429,95 @@ function makeIndicatorGraph() { ...@@ -278,248 +429,95 @@ function makeIndicatorGraph() {
yaxis.transition() yaxis.transition()
.duration(500) .duration(500)
.call(d3.axisLeft(yLine) .call(d3.axisLeft(yLine)
/*.tickFormat(d3.format(".2s"))*/ .tickFormat(yAxisFormat));
);
// color axis labels // color axis labels
g.selectAll(".y.axis g.tick text") g.selectAll(".y.axis g.tick text")
.style("fill", "#b2b2b2"); // function (d,i) {return (i%2)?"red":"blue";})
let title = selection.select(".title.label");
title.text(chart.title())
.style("fill", "#b2b2b2"); .style("fill", "#b2b2b2");
selection.select(".title.label") // define line
.append("tspan") let line = d3.line()
.attr("class", "far") .defined(d => d)
.html(" \uf059") .curve(d3.curveMonotoneX)
//.style("color", "#b2b2b2") .x(d => xLine(d.date))
.style("cursor", "pointer") .y(d => yLine(d.value));
.on("click", () => { // when clicking ? display modal with information about indicator
$("#explainIndicatorModal").on("show.bs.modal", () => { // get lines
let indicatorName = indicatorsNames[indicators.indexOf(id)] let lines = g.select(".lines");
$("#explainIndicatorModal").find("#explainIndicatorModalTitle").text(indicatorName); lines.selectAll("path.line")
$("#explainIndicatorModal").find(".modal-body").html(indicatorVars[id].explanation); .data(filteredData)
}); .join("path") // handle enter, update, and exit automagically
$("#explainIndicatorModal").modal(); .attr("stroke", (d, i) => {
}); return i == 0 ? defaultLineColor : lineColors(i - 1);
//});
// update chart
updateData = function () {
let time = map.timeDimension.getCurrentTime();
// update data ranges using values from displayName and lineVariables
minDate = d3.min(data[0].values, d => {
return d[displayName];
});
minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment
maxDate = d3.max(data[0].values, d => {
return d[displayName];
});
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
// update axes' domain
xLine.domain([minDate, maxDate])
//.nice()
//.nice(d3.timeMonth)
.range([0, width - margin.left - margin.right - 30])
.clamp(true);
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; }))
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice()
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value));
yLine.domain([0, maxDomain])
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice()
.range([height - margin.left - margin.right, 0 + 35])
.nice();
// filter data to only use the ones needed for current time
let filteredData = [];
data.forEach((d, i) => {
filteredData.push({
name: d.name,
values: []
});
d.values.filter(v => {
if (v.date <= new Date(time)) {
filteredData[i].values.push(v);
}
});
}) })
.attr("class", "line")
// update axes .attr("fill", "none")
let g = selection.select(".lineChart"); .attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
// update axis line with no ticks .attr("stroke-width", 1.5)
let xaxis = g.select(".x.axis"); .attr("d", d => line(d.values))
xaxis.transition()
.duration(500) // get circles
.call( let circles = g.select(".circles"),
d3.axisBottom(xLine) tooltip = d3.select(".tooltip");
.ticks(0) //tooltipFormat = d3.timeFormat("%b "%y"),
.tickSize(0) //tooltipFormat = d3.format(",.2f")
); //tooltipFormat = d3.format(",.3s");
// update axis ticks - one for each month circles.selectAll("g") // using nested data, so need to make a g to contain stuff
let xaxisTicks = g.select(".x.axis-ticks"); .data(filteredData)
let monthsInGraph = []; .join( // handle enter, update, and exit separately for overall g circle containers
userDates.forEach(d => { enter => enter
monthsInGraph.push(new Date(d)); .append("g")
}); .attr("class", d => d.name)
.attr("stroke", (d, i) => {
xaxisTicks.transition() return i == 0 ? defaultPointColor : pointColors(i - 1);
.duration(500)
.call(
d3.axisBottom(xLine)
.tickValues(monthsInGraph)
.tickFormat("")
);
// update axis month labels depending on how many months there are
let xaxisLabels = g.select(".x.axis-month-labels");
// FIXME: check how this displays ticks when there are many months/years
// this fix gives up to 10 ticks
// maybe need to set up more conditions
let numberOfTicks = monthsInGraph.length < 6 ? d3.timeMonth.every(1) : 6;
xaxisLabels.transition().duration(500)
.call(
d3.axisBottom(xLine)
.ticks(numberOfTicks)
.tickFormat(d3.timeFormat("%b"))
)
.selectAll("text")
.style("fill", "#b2b2b2")
.attr("font-size", "12px");
// update axis year labels depending on how many months there are
let xaxisYearLabels = g.select(".x.axis-year-labels");
xaxisYearLabels.transition().duration(500)
.call(
d3.axisBottom(xLine)
.ticks(numberOfTicks)
.tickFormat(d3.timeFormat("'%y"))
)
.selectAll("text")
.style("fill", "#b2b2b2")
.attr("font-size", "12px");
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis.selectAll("g.tick line")
.attr("y2", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return -height - 6;
else
return 6;
})
.attr("transform", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "translate(0,6)";
}) })
.attr("class", d => { // d is the tick value .attr("fill", (d, i) => {
if (d3.timeFormat("%m")(d) == "01") //if it is Jan return i == 0 ? defaultPointColor : pointColors(i - 1);
return "yearTick"; }),
}); update => update
.attr("class", d => d.name)
let yaxis = g.select(".y.axis");
yaxis.transition()
.duration(500)
.call(d3.axisLeft(yLine)
.tickFormat(yAxisFormat));
// color axis labels
g.selectAll(".y.axis g.tick text")
.style("fill", "#b2b2b2");
// define line
let line = d3.line()
.defined(d => d)
.curve(d3.curveMonotoneX)
.x(d => xLine(d.date))
.y(d => yLine(d.value));
// get lines
let lines = g.select(".lines");
lines.selectAll("path.line")
.data(filteredData)
.join("path") // handle enter, update, and exit automagically
.attr("stroke", (d, i) => { .attr("stroke", (d, i) => {
return i == 0 ? defaultLineColor : lineColors(i - 1); return i == 0 ? defaultPointColor : pointColors(i - 1);
}) })
.attr("class", "line") .attr("fill", (d, i) => {
.attr("fill", "none") return i == 0 ? defaultPointColor : pointColors(i - 1);
.attr("stroke-linejoin", "round") }),
.attr("stroke-linecap", "round") exit => exit.remove()
.attr("stroke-width", 1.5) )
.attr("d", d => line(d.values)) // nested join
.selectAll("circle").data(d => d.values) // access internal values array for circles here
// get circles .join( // handle enter, update, and exit separately for circles
let circles = g.select(".circles"), enter => enter
tooltip = d3.select(".tooltip"); .append("circle")
//tooltipFormat = d3.timeFormat("%b "%y"), .attr("class", "circle")
//tooltipFormat = d3.format(",.2f") .attr("r", 2.5)
//tooltipFormat = d3.format(",.3s"); .attr("cx", d => xLine(d.date))
.attr("cy", d => yLine(d.value))
circles.selectAll("g") // using nested data, so need to make a g to contain stuff .on("mouseover", d => {
.data(filteredData) tooltip.html(`${tooltipFormat(d.value)} ${tooltipUnits}`);
.join( // handle enter, update, and exit separately for overall g circle containers let tpWidth = tooltip.node().offsetWidth; // to center tooltip
enter => enter tooltip.style("left", `${d3.event.pageX - tpWidth / 2}px`)
.append("g") .style("top", `${d3.event.pageY - 23}px`)
.attr("class", d => d.name) .style("font-family", "Consolas, courier")
.attr("stroke", (d, i) => { .style("font-size", "10pt")
return i == 0 ? defaultPointColor : pointColors(i - 1); .transition()
}) .duration(200)
.attr("fill", (d, i) => { .style("opacity", .9);
return i == 0 ? defaultPointColor : pointColors(i - 1); })
}), .on("mouseout", () => {
update => update tooltip.transition()
.attr("class", d => d.name) .duration(500)
.attr("stroke", (d, i) => { .style("opacity", 0);
return i == 0 ? defaultPointColor : pointColors(i - 1); }),
}) update => update
.attr("fill", (d, i) => { .attr("cx", d => xLine(d.date))
return i == 0 ? defaultPointColor : pointColors(i - 1); .attr("cy", d => yLine(d.value)),
}), exit => exit.remove()
exit => exit.remove() );
) }
// nested join });
.selectAll("circle").data(d => d.values) // access internal values array for circles here
.join( // handle enter, update, and exit separately for circles
enter => enter
.append("circle")
.attr("class", "circle")
.attr("r", 2.5)
.attr("cx", d => xLine(d.date))
.attr("cy", d => yLine(d.value))
.on("mouseover", d => {
tooltip.html(`${tooltipFormat(d.value)} ${tooltipUnits}`);
let tpWidth = tooltip.node().offsetWidth; // to center tooltip
tooltip.style("left", `${d3.event.pageX - tpWidth / 2}px`)
.style("top", `${d3.event.pageY - 23}px`)
.style("font-family", "Consolas, courier")
.style("font-size", "10pt")
.transition()
.duration(200)
.style("opacity", .9);
})
.on("mouseout", () => {
tooltip.transition()
.duration(500)
.style("opacity", 0);
}),
update => update
.attr("cx", d => xLine(d.date))
.attr("cy", d => yLine(d.value)),
exit => exit.remove()
);
}
});
//});
} }
chart.width = function(value) { chart.width = function(value) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment