Skip to content

Instantly share code, notes, and snippets.

@jorgeatgu
Last active December 15, 2018 15:04
Show Gist options
  • Save jorgeatgu/72671381fd2440400adf0c13de848fb4 to your computer and use it in GitHub Desktop.
Save jorgeatgu/72671381fd2440400adf0c13de848fb4 to your computer and use it in GitHub Desktop.
Gráfica de area con tooltip II
license: mit
const areaTooltipDue = () => {
//Estructura similar a la que utilizan en algunos proyectos de pudding.cool
const margin = { top: 24, right: 24, bottom: 24, left: 24 };
let width = 0;
let height = 0;
const chart = d3.select('.chart-lluvia-tooltip-dos');
const svg = chart.select('svg');
const scales = {};
let dataz;
const bisectDate = d3.bisector(d => d.fecha).left;
const tooltipDates = chart.append("div")
.attr("class", "tooltip tooltip-lluvias")
.style("opacity", 0);
//Escala para los ejes X e Y
const setupScales = () => {
const countX = d3.scaleTime()
.domain([d3.min(dataz, d => d.fecha
),
d3.max(dataz, d => d.fecha)
]);
const countY = d3.scaleLinear()
.domain([0, 60]);
scales.count = { x: countX, y: countY };
}
//Seleccionamos el contenedor donde irán las escalas y en este caso el area donde se pirntara nuestra gráfica
const setupElements = () => {
const g = svg.select('.chart-lluvia-tooltip-dos-container');
g.append('g').attr('class', 'axis axis-x');
g.append('g').attr('class', 'axis axis-y');
g.append('g').attr('class', 'area-container-dos');
g.append('rect').attr('class', 'overlay');
g.append('g').attr('class', 'focus')
.style("display", "none")
.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0);
g.select('.focus').append("text")
.attr("class", "text-focus");
}
//Actualizando escalas
const updateScales = (width, height) => {
scales.count.x.range([0, width]);
scales.count.y.range([height, 0]);
}
//Dibujando ejes
const drawAxes = (g) => {
const axisX = d3.axisBottom(scales.count.x)
.tickFormat(d3.format("d"))
.ticks(13)
g.select(".axis-x")
.attr("transform", "translate(0," + height + ")")
.call(axisX)
const axisY = d3.axisLeft(scales.count.y)
.tickFormat(d3.format("d"))
.ticks(5)
.tickSizeInner(-width)
g.select(".axis-y")
.call(axisY)
const focus = g.select('.focus');
const overlay = g.select('.overlay');
const focusText = g.select('text-focus')
focus.select(".x-hover-line").attr("y2", height);
focusText.attr("x", -10)
.attr("y", -20)
.attr("dy", ".31em");
overlay.attr("width", width + margin.left + margin.right)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none")
tooltipDates.style("opacity", 0)
})
.on("mousemove", mousemove);
function mousemove() {
const w = chart.node().offsetWidth;
var x0 = scales.count.x.invert(d3.mouse(this)[0]),
i = bisectDate(dataz, x0, 1),
d0 = dataz[i - 1],
d1 = dataz[i],
d = x0 - d0.fecha > d1.fecha - x0 ? d1 : d0;
//Calculamos la posicion del tooltip
const positionX = scales.count.x(d.fecha) + 25;
const postionWidthTooltip = positionX + 300;
const positionRightTooltip = w - positionX;
tooltipDates.style("opacity", 1)
.html('<p class="tooltipYear"><span class="textYear">' + d.fecha + '</span>En <span>' + d.dias + '</span> días de lluvia se recogieron <span>' + d.precipitacion_anual + '</span> milímetros de agua.<p/>')
//Dependiendo de la posición del tooltip cambiamos su sentido para que sea legible
.style("left", postionWidthTooltip > w ? 'auto' : positionX + 'px')
.style("right", postionWidthTooltip > w ? positionRightTooltip + 'px' : 'auto');
focus.select(".x-hover-line")
.attr("transform",
"translate(" + scales.count.x(d.fecha) + "," +
0 + ")");
}
}
function updateChart(datazz) {
const w = chart.node().offsetWidth;
const h = 600;
width = w - margin.left - margin.right;
height = h - margin.top - margin.bottom;
svg
.attr('width', w)
.attr('height', h);
const translate = "translate(" + margin.left + "," + margin.top + ")";
const g = svg.select('.chart-lluvia-tooltip-dos-container')
g.attr("transform", translate)
const area = d3.area()
.x(d => scales.count.x(d.fecha))
.y0(height)
.y1(d => scales.count.y(d.dias))
.curve(d3.curveCardinal.tension(0.6));
updateScales(width, height)
const container = chart.select('.area-container-dos')
const layer = container.selectAll('.area')
.data([dataz])
const newLayer = layer.enter()
.append('path')
.attr('class', 'area area-bgc2')
layer.merge(newLayer)
.attr('d', area)
drawAxes(g)
}
const resize = () => {
updateChart(dataz)
}
// LOAD THE DATA
const loadData = () => {
d3.csv('dias-de-lluvia.csv', (error, data) => {
if (error) {
console.log(error);
} else {
dataz = data
dataz.forEach(d => {
d.fecha = d.fecha;
d.dias_lluvia = d.dias;
});
setupElements()
setupScales()
updateChart(dataz)
}
});
}
window.addEventListener('resize', resize)
loadData()
}
areaTooltipDue()
fecha dias precipitacion_anual
1951 19 123
1952 34 123
1953 44 123
1954 37 123
1955 33 123
1956 43 123
1957 34 123
1958 18 123
1959 17 123
1960 14 123
1961 18 123
1962 33 123
1963 48 123
1964 45 123
1965 28 123
1966 17 123
1967 33 123
1968 16 123
1969 34 123
1970 26 123
1971 33 123
1972 21 123
1973 35 123
1974 24 123
1975 21 123
1976 28 123
1977 08 123
1978 16 123
1979 26 123
1980 24 123
1981 24 123
1982 07 123
1983 38 123
1984 12 123
1985 40 123
1986 08 123
1987 18 123
1988 20 123
1989 18 123
1990 25 123
1991 25 123
1992 29 123
1993 22 123
1994 11 123
1995 16 123
1996 12 123
1997 08 123
1998 26 123
1999 28 123
2000 23 123
2001 22 123
2002 10 123
2003 20 123
2004 12 123
2005 47 123
2006 28 123
2007 19 123
2008 15 123
2009 17 123
2010 32 123
2011 16 123
2012 23 123
2013 25 123
2014 07 123
2015 12 123
2016 07 123
2017 10 123
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Clau | area tooltip II</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="styles.css">
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700|Rubik:400,500|Adamina" rel="stylesheet">
</head>
<body>
<section class="clau-container bg2">
<section class="chart-container">
<h3 class="subtitle">
Gráfica de Area con tooltip II</h3>
<p class="text">Con un tooltip que devuelve texto y una línea para ubicar al usuario en la gráfica.</p>
<article class="chart-lluvia-tooltip-dos">
<svg>
<g class="chart-lluvia-tooltip-dos-container"></g>
</svg>
</article>
</section>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<script src="area-tooltip-dos.js"></script>
</body>
</html>
/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}:root{--fontSystem:BlinkMacSystemFont,-apple-system,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",Helvetica,sans-serif;--monospace:"SFMono-Regular",Consolas,Menlo,Courier,monospace;--roboto:"Roboto Condensed",sans-serif;--archivo:"Rubik",sans-serif;--adamina:"Adamina",serif;--black:#111;--white:#fff;--f1:#f1f1f1;--background:#dde8e0;--wes-grey:#b3c0c3;--wes-red:#f23818;--wes-blue:#0097e2;--wes-bluedark:#182956;--wes-gold:#ddb289;--area:#3a285d;--wes-bg1:#cfca9e;--wes-bgc1:#c96553;--wes-bg2:#dde8e0;--wes-bgc2:#759ca7;--wes-bg3:#fbd5c5;--wes-bgc3:#360c05;--wes-bg4:#d5d5d3;--wes-bgc4:#cdaa27;--wes-bg5:#faefd2;--wes-bgc5:#8a9da4;--wes-bg6:#ccc494;--wes-bgc6:#29211f;--wes-bg7:#d3dddc;--wes-bgc7:#456455}.axis-x,.axis-y{font-family:Roboto Condensed,sans-serif;font-family:var(--roboto)}.axis-x .domain,.axis-y .domain{stroke:none}.axis-y .tick line{stroke:#888;stroke-dasharray:3px 3px}.area{fill:#3a285d;fill:var(--area)}.area-bgc1{fill:#c96553;fill:var(--wes-bgc1)}.bg1{background-color:#cfca9e;background-color:var(--wes-bg1)}.area-bgc2{fill:#759ca7;fill:var(--wes-bgc2)}.bg2{background-color:#dde8e0;background-color:var(--wes-bg2)}.bar-bgc3{fill:#360c05;fill:var(--wes-bgc3)}.bg3{background-color:#fbd5c5;background-color:var(--wes-bg3)}.bar-bgc4{fill:#cdaa27;fill:var(--wes-bgc4)}.bg4{background-color:#d5d5d3;background-color:var(--wes-bg4)}.bar-bgc5{fill:#8a9da4;fill:var(--wes-bgc5)}.bg5{background-color:#faefd2;background-color:var(--wes-bg5)}.scatter-bgc6{fill:#29211f;fill:var(--wes-bgc6)}.bg6{background-color:#ccc494;background-color:var(--wes-bg6)}.area-bgc7{fill:#456455;fill:var(--wes-bgc7)}.bg7{background-color:#d3dddc;background-color:var(--wes-bg7)}.x-hover-line,.y-hover-line{stroke:#f23818;stroke:var(--wes-red)}.circle-focus{fill:#f23818;fill:var(--wes-red)}.text-focus{font-family:Roboto Condensed,sans-serif;font-family:var(--roboto);font-size:12px}.overlay{fill:transparent}.chart-lluvia-tooltip-dos{position:relative}.tooltip{position:absolute;z-index:1;width:70px;margin-left:20px;padding:10px;border-radius:3px}.tooltip-lluvias{background-color:#8b8379;height:auto;width:300px;border-color:#8b8379;margin-left:0;top:150px}.tooltip-lluvias p:empty{display:none}.tooltip-lluvias .tooltipYear{color:#fff;color:var(--white);font-size:1.1rem;font-weight:400;max-width:300px}.tooltip-lluvias .tooltipYear .textYear{display:block;font-size:1.3rem}.tooltip-lluvias .tooltipYear span{font-weight:700;font-family:SFMono-Regular,Consolas,Menlo,Courier,monospace;font-family:var(--monospace)}.chart-lluvia-bar-vertical-tooltip{position:relative}.tooltip-lluvia-mes-container{position:absolute;font-family:Roboto Condensed,sans-serif;font-family:var(--roboto);border-top-right-radius:5px;border-bottom-right-radius:5px;padding:5px 15px;border-left:5px solid #34009c;background-color:#f3f3f3;box-shadow:0 3px 4px rgba(0,0,0,.2);top:5%;left:50%;transform:translate(-50%,-50%)}.tooltip-lluvia-mes{font-size:16px;color:#34009c}.tooltip-lluvia-mes-total{font-weight:700}@media only screen and (min-width:48em){.axis-x,.axis-y{font-size:14px}}.line{fill:none;stroke:#3a285d;stroke:var(--area)}*{box-sizing:border-box;line-height:1.5}h1,h2,h3,h4,h5,h6,p,span{text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}body{background-color:#dde8e0;background-color:var(--background)}.clau-container{margin:0 auto;width:100%;padding:2rem 0}.clau-container-full{max-width:90%;margin:0 auto}.chart-container{max-width:90vw;margin:2rem auto 6rem}.subtitle,.title{font-size:2rem;font-family:Rubik,sans-serif;font-family:var(--archivo);color:#182956;color:var(--wes-bluedark);text-transform:uppercase;letter-spacing:1px}.quote{padding:1rem;background-color:#fff;background-color:var(--white);border-left:5px solid #182956;border-left:5px solid var(--wes-bluedark)}.title{margin-bottom:1rem}.subtitle{font-size:1.5rem;margin-bottom:0}.text{font-size:1rem;font-family:Adamina,serif;font-family:var(--adamina);color:#111;color:var(--black);max-width:30rem}.footer{background-color:#e25772;width:100%;padding:10vh 0}.footer-links,.footer-texto{color:#111;color:var(--black);font-family:Roboto Condensed,sans-serif;font-family:var(--roboto);font-size:1rem}.footer-links{font-weight:700}@media only screen and (min-width:48em){.subtitle,.title{letter-spacing:0}.title{font-size:4rem}.chart-container{max-width:60rem}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment