简体   繁体   中英

D3 mouseover event is not triggered on the bottom elements

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).

  • I re-sized the SVG then played with the padding and margin with not luck.
  • I also tried calling tooltip indenpently also with no luck

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM