The code below is relates to a heat map. I added a tooltip to the svg, however, the mouseover event is NOT triggered for all elements on the graph. The tooltip is not being displayed for last row (Represents December Months).
Can someone point me in the right direction?
For live app Click Here
$(document).ready(function() {
$.getJSON(
'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json',
function(data) {
const width = 900
const height = 600
let dataset = []
const baseTemp = data.baseTemperature
data.monthlyVariance.forEach((entry) => {
dataset.push([ entry.year, entry.month - 1, entry.variance ])
})
const maxYear = (d3.max(dataset, d => d[0]) + 2)
const minYear = d3.min(dataset, d => d[0])
const colorDomain = [ 1,2,3,4,5,6,7,8,9,10,11,12,13 ]
const colorRange = [
'#3d86d3',
'#47a9c1',
'#58d3c5',
'#3fc18b',
'#3fc162',
'#86ba50',
'#7fc141',
'#98c43a',
'#a9c140',
'#c4b121',
'#d1801d',
'#d1491b',
'#d1361b'
]
let xScale = d3
.scaleLinear()
.domain([ minYear, maxYear ])
.range([ 0, width ])
let yScale = d3
.scaleLinear()
.domain([ 11 , 0 ])
.range([ height , 0 ])
let colorScale = d3.scaleQuantile()
.domain(colorDomain)
.range(colorRange)
let monthFormatter = d3.timeFormat('%B')
let tickFormatter = (month) => {
return monthFormatter(new Date(minYear, month))
}
const xAxis = d3.axisBottom(xScale).tickFormat(d3.format('d'))
const yAxis = d3.axisLeft(yScale).tickFormat(tickFormatter).tickSize([ 0 ])
var tooltip = d3
.select('.chart')
.append('div')
.attr('id', 'tooltip')
let svg = d3.select('.chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.style('padding', '40 20 140 150')
svg
.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
.attr('x', d => xScale(d[0]))
.attr('y', d => yScale(d[1]))
.attr('width', 4)
.attr('height', (height/10))
.attr('class', 'cell')
.attr('fill', d => {
return colorScale(Math.floor(baseTemp + d[2]))
})
.attr('data-year', d => d[0])
.attr('data-month', d => d[1])
.attr('data-temp', d => (d[2] + baseTemp))
.on('mouseover', (d) => {
tooltip
.transition()
.style('opacity', 1)
.style('visibility', 'visible')
tooltip
.attr('data-year', d[0])
.html(d[0] + ', ' + monthFormatter(new Date(d[0],d[1]))+'</br>')
.style('left', (d3.event.pageX + 10) + 'px')
.style('top', (d3.event.pageY + 10) + 'px')
})
svg.on('mouseout', () => {
tooltip.transition().style('visibility', 'hidden')
})
}
)
})
Your SVG area is not big enough to hold last row of those RECT, the last row of rect is out of event area.Just set the height of SVG to hold the last row.
You set the range from 0-height, and use it as the y attr of rect which means the last row will go over the SVG's area, when you mouseover that last row area, it actually only mouseover svg element, so the event bubbling up from SVG to outside div , no event from those rect elements inside, so no mouseover event handler triggerred
you have to adjust the domain of the yScale
.
you call it with the number 0..11 but you want to have room to show month 11 so the domain spans to 12.
let yScale = d3
.scaleLinear()
.domain([ 12, 0 ])
.range([height , 0]);
To calculate the height of the rectangles use the yScale
.attr('height', yScale(1)-yScale(0))
You could use a similar trick to calculate the width of the rect based on the domain of X.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.