d3 工具提示和画笔不能一起工作

时间:2021-02-17 16:15:06

标签: javascript d3.js

我有一个带有工具提示和画笔的类,我使用的是 d3 版本 4,我的代码如下

var allData = [{
        value: 10,
        time: 1613579385
    }, {
        value: 15,
        time: 1613492985
    }, {
        value: 20,
        time: 1613406585
    }, {
        value: 30,
        time: 1613320185
    }, {
        value: 10,
        time: 1613589385
    }, {
        value: 15,
        time: 1613482985
    }, {
        value: 20,
        time: 1613486585
    }, {
        value: 30,
        time: 1613380185
    }
]
var margin = {
    top: 20,
    right: 10,
    bottom: 50,
    left: 50
};
var width = 600, height = 600;
var colors = ['#c0485c', '#4682b4'];
var svg = d3.select("body")
    .append('svg')
    .attr('class', 'ellipse')
    .attr('width', width + margin.left + margin.right + 100)
    .attr('height', height + margin.top + margin.bottom);
var gElement = svg.append('g')
    .attr('transform', `translate(${margin.left},${margin.top})`);
var xScale = d3.scaleTime().range([margin.left, width]);
var yScale = d3.scaleLinear().range([height, margin.bottom]);

xScale.domain(d3.extent(allData, (d) => new Date(d.time * 1000)));
yScale.domain(d3.extent(allData, (d) => d.value));

var xAxis = gElement.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + (height) + ')')
    .call(d3.axisBottom(xScale));

gElement.append('text')
.attr('transform', 'translate(' + (width / 2) + ' ,' + (height + margin.top + 20) + ')')
.style('text-anchor', 'middle').text('time');

var yAxis = gElement.append('g')
    .attr('class', 'axis axis--y')
    .attr('transform', 'translate(' + (margin.left) + ',0)')
    .call(d3.axisLeft(yScale));

// text label for the y axis
gElement.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', 0 - (height / 2)).attr('dy', '1em')
.style('text-anchor', 'middle').text('Unit');

var circleCx = (d) => xScale(d && d.time ? new Date(d.time * 1000) : new Date(0));
var circleCy = (d) => yScale(d && d.value ? d.value : 0);

var clip = gElement.append("defs").append("svg:clipPath")
    .attr("id", "clip")
    .append("svg:rect")
    .attr("width", width)
    .attr("height", height)
    .attr("x", margin.left)
    .attr("y", margin.bottom);

var circles = gElement.append('g')
    .attr("clip-path", "url(#clip)");

var focus = gElement.append('g')
    .attr('class', 'tooltip')
    .style('display', 'none');
focus.append('rect')
.attr('class', 'tooltip-box')
.attr('width', 300)
.attr('height', 60);

focus.append('text').attr('class', 'tooltip-date');
focus.append('text').attr('class', 'tooltip-value');

focus.append('circle')
.attr('class', 'tooltip-point')
.style('stroke', 'white')
.style('stroke-width', '.5')
.attr('r', 6);

function onMouseOver(data) {
    if (!data || !data.time) {
        return;
    }
    focus.style('display', null);
    focus.select('circle.tooltip-point').attr('transform', `translate(${xScale(new Date(data.time * 1000))},${yScale(data.value)})`);
    const translateX = xScale(new Date(data.time * 1000));
    const translateY = yScale(data.value);

    focus.select('rect.tooltip-box')
    .attr('transform', `translate(${translateX},  ${translateY})`)
    .attr('x', 2)
    .attr('y', -2.5);

    focus.select('text.tooltip-date')
    .attr('transform', `translate(${translateX},  ${translateY})`)
    .attr('dx', 10)
    .attr('dy', 30)
    .text(`Date: ${new Date(data.time * 1000)}`);

    focus.select('text.tooltip-value')
    .attr('transform', `translate(${translateX},  ${translateY})`)
    .attr('dx', 10)
    .attr('dy', 45)
    .text(`Value: ${data.value}`);
}

function onMouseOut() {
    focus.style('display', 'none')
}

var points = circles.selectAll(`.circle-data`)
    .data(allData)
    .enter()
    .append('circle') // enter append
    .attr('class', `circle-data`)
    .attr('stroke', 'blue')
    .attr('r', '3') // radius
    .attr('cx', circleCx)
    .attr('cy', circleCy)

function applyZoom() {
    var brush = d3.brushX()
        .extent([[margin.left, margin.bottom], [width, height]])
        .on("end", () => {
        const extent = d3.event.selection;

        if (extent) {
            xScale.domain([xScale.invert(extent[0]), xScale.invert(extent[1])]);

            circles.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done


        }

        xAxis.transition().duration(1000).call(d3.axisBottom(this.xScale))

        circles.selectAll('.circle-data')
        .transition()
        .duration(1000)
        .attr('cx', circleCx)
        .attr('cy', circleCy)

    });

    circles.append("g")
    .attr("class", "brush")
    .call(brush)

    svg.on("dblclick", () => {
        xScale.domain(d3.extent(allData, (d) => new Date(d.time * 1000)));
        xAxis.transition().call(d3.axisBottom(xScale));
        d3.selectAll('circle')
        .transition()
        .attr('cx', circleCx)
        .attr('cy', circleCy)
    });
}
applyZoom();

gElement.selectAll('.brush')
.on('mouseover', onMouseOver)
.on('mouseout', onMouseOut);

当我可以通过选择 svg 进行缩放时不显示工具提示。缩放有效,但不能与工具提示一起使用。如果我删除 zoom ,则工具提示正常工作。注释掉 applyZoom 方法提供了一个有效的工具提示。

完整代码可在小提琴中找到:https://jsfiddle.net/edayan/9chrn536/1/

0 个答案:

没有答案