async function drawLineChart() {
let dataset = await d3.json("https://gist.githubusercontent.com/chekos/7ee802ef53ba4bbd10a3b8161116d638/raw/e0d655473a57fae5ba54e648429bfd01ca698e12/tijuana_weather_data.json")
const yAccessor = d => d.temperatureMax
const dateParser = d3.timeParse("%Y-%m-%d")
const xAccessor = d => dateParser(d.date)
dataset = dataset.sort((a,b) => xAccessor(a) - xAccessor(b)).slice(0, 100)
let dimensions = {
width: width * 0.90,
height: 400,
margin: {
top: 15,
right: 15,
bottom: 40,
left: 60,
},
}
dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right
dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom
const wrapper = d3.select("#wrapper")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height)
const bounds = wrapper.append("g")
.attr("transform", `translate(${dimensions.margin.left}, ${dimensions.margin.top})`)
bounds.append("defs").append("clipPath")
.attr("id", "bounds-clip-path")
.append("rect")
.attr("width", dimensions.boundedWidth)
.attr("height", dimensions.boundedHeight)
const clip = bounds.append("g")
.attr("clip-path", "url(#bounds-clip-path)")
// escalas
const yScale = d3.scaleLinear()
.domain(d3.extent(dataset, yAccessor))
.range([dimensions.boundedHeight, 0])
.nice()
const freezingTemperaturePlacement = yScale(32)
const freezingTemperatures = clip.append("rect")
.attr("class", "freezing")
.attr("x", 0)
.attr("width", d3.max([0, dimensions.boundedWidth]))
.attr("y", freezingTemperaturePlacement)
.attr("height", d3.max([0, dimensions.boundedHeight - freezingTemperaturePlacement]))
const xScale = d3.scaleTime()
.domain(d3.extent(dataset, xAccessor))
.range([0, dimensions.boundedWidth])
.nice()
// Dibujar datos
const lineGenerator = d3.line()
.x(d => xScale(xAccessor(d)))
.y(d => yScale(yAccessor(d)))
const line = clip.append("path")
.attr("class", "line")
.attr("d", lineGenerator(dataset))
// Periferales y detalles
const yAxisGenerator = d3.axisLeft()
.scale(yScale)
const yAxis = bounds.append("g")
.attr("class", "y-axis")
.call(yAxisGenerator)
const yAxisLabel = yAxis.append("text")
.attr("class", "y-axis-label")
.attr("x", -dimensions.boundedHeight / 2)
.attr("y", -dimensions.margin.left + 10)
.html("Temperatura Maxima (° F)")
const xAxisGenerator = d3.axisBottom()
.scale(xScale)
const xAxis = bounds.append("g")
.attr("class", "x-axis")
.style("transform", `translateY(${dimensions.boundedHeight}px)`)
.call(xAxisGenerator)
// Interacciones
const listentingRect = bounds.append("rect")
.attr("class", "listening-rect")
.attr("width", dimensions.boundedWidth)
.attr("height", dimensions.boundedHeight)
.on("mousemove", onMouseMove)
.on("mouseleave", onMouseLeave)
const tooltip = d3.select("#tooltip")
const formatDate = d3.timeFormat("%B %A %-d, %Y")
const formatTemperature = d => `${d3.format(".1f")(d)} °F`
const tooltipCircle = bounds.append("circle")
.attr("r", 4)
.attr("stroke", "#AF9358")
.attr("fill", "white")
.attr("stroke-width", 2)
.attr("opacity", 0)
function onMouseMove() {
const mousePosition = d3.mouse(this)
const hoveredDate = xScale.invert(mousePosition[0])
const getDistanceFromHoveredDate = d => Math.abs(xAccessor(d) - hoveredDate)
const closestIndex = d3.scan(dataset, (a, b) => (
getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b)
))
const closestDataPoint = dataset[closestIndex]
const closestXValue = xAccessor(closestDataPoint)
const closestYValue = yAccessor(closestDataPoint)
tooltip.select("#date")
.text(formatDate(closestXValue))
tooltip.select("#temperature")
.text(formatTemperature(closestYValue))
const x = xScale(closestXValue) + dimensions.margin.left
const y = yScale(closestYValue) + dimensions.margin.top
tooltip.style("transform", `translate( calc(-50% + ${x}px), calc(-100% + ${y}px))`)
tooltip.style("opacity", 1)
tooltipCircle
.attr("cx", xScale(closestXValue))
.attr("cy", yScale(closestYValue))
.style("opacity", 1)
}
function onMouseLeave() {
tooltip.style("opacity", 0)
tooltipCircle.style("opacity", 0)
}
}