async function drawScatter() {
const dataset = await d3.json("https://gist.githubusercontent.com/chekos/7ee802ef53ba4bbd10a3b8161116d638/raw/e0d655473a57fae5ba54e648429bfd01ca698e12/tijuana_weather_data.json")
const xAccessor = d => d.dewPoint
const yAccessor = d => d.humidity
let dimensions = {
width: width * .75,
height: width * .75,
margin: {
top: 40,
right: 10,
bottom: 50,
left: 50,
},
}
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")
.style("transform", `translate(${dimensions.margin.left}px, ${dimensions.margin.top}px)`)
const xScale = d3.scaleLinear()
.domain(d3.extent(dataset, xAccessor))
.range([0, dimensions.boundedWidth])
.nice()
const yScale = d3.scaleLinear()
.domain(d3.extent(dataset, yAccessor))
.range([dimensions.boundedHeight, 0])
.nice()
const drawDots = (dataset) => {
// dibujar datos
const dots = bounds.selectAll("circle")
.data(dataset, d => d[0])
const newDots = dots.enter().append("circle")
const allDots = newDots.merge(dots)
.attr("cx", d => xScale(xAccessor(d)))
.attr("cy", d => yScale(yAccessor(d)))
.attr("r", 4)
const oldDots = dots.exit()
.remove()
}
drawDots(dataset)
// voronoi
const voronoiGenerator = d3.voronoi()
.x(d => xScale(xAccessor(d)))
.y(d => yScale(yAccessor(d)))
.extent([ [0,0], [dimensions.boundedWidth, dimensions.boundedHeight]])
const voronoiPolygons = voronoiGenerator.polygons(dataset)
bounds.selectAll(".voronoi")
.data(voronoiPolygons)
.enter().append("polygon")
.attr("class", "voronoi")
.attr("points", (d = []) => (
d.map(point => (
point.join(",")
)).join(" ")
))
//.attr("stroke", "salmon")
.on("mouseenter", onMouseEnter)
.on("mouseleave", onMouseLeave)
// Agrega los detalles periferales
const xAxisGenerator = d3.axisBottom()
.scale(xScale)
const xAxis = bounds.append("g")
.call(xAxisGenerator)
.style("transform", `translateY(${dimensions.boundedHeight}px)`)
const xAxisLabel = xAxis.append("text")
.attr("class", "x-axis-label")
.attr("x", dimensions.boundedWidth / 2)
.attr("y", dimensions.margin.bottom - 10)
.html("dew point (° F)")
const yAxisGenerator = d3.axisLeft()
.scale(yScale)
.ticks(4)
const yAxis = bounds.append("g")
.call(yAxisGenerator)
const yAxisLabel = yAxis.append("text")
.attr("class", "y-axis-label")
.attr("x", -dimensions.boundedHeight / 2)
.attr("y", -dimensions.margin.left + 10)
.text("relative humidity")
// interacciones
bounds.selectAll("circle")
.on("mouseenter", onMouseEnter)
.on("mouseleave", onMouseLeave)
const tooltip = d3.select("#tooltip")
const formatHumidity = d3.format(".2f")
const formatDewPoint = d3.format(".2f")
const dateParser = d3.timeParse("%Y-%m-%d")
const formatDate = d3.timeFormat("%B %A %-d, %Y")
function onMouseEnter(voronoiDatum, index) {
const datum = voronoiDatum.data
const dayDot = bounds.append("circle")
.attr("class", "tooltipDot")
.attr("cx", d => xScale(xAccessor(datum)))
.attr("cy", d => yScale(yAccessor(datum)))
.attr("r", 7)
.style("fill", "maroon")
.style("pointer-events", "none")
tooltip.select("#humidity")
.text(formatHumidity(xAccessor(datum)))
tooltip.select("#dew-point")
.text(formatDewPoint(yAccessor(datum)))
tooltip.select("#date")
.text(formatDate(dateParser(datum.date)))
const x = xScale(xAccessor(datum)) + dimensions.margin.left
const y = yScale(yAccessor(datum)) + dimensions.margin.top
tooltip.style("transform", `translate( calc(-50% + ${x}px), calc( -100% + ${y}px))`)
tooltip.style("opacity", 1)
}
function onMouseLeave() {
tooltip.style("opacity", 0)
d3.selectAll(".tooltipDot")
.remove()
}
}