如何使用 D3.js v4 使时间轴上的元素跟随缩放

How to have elements on a timeline follow zooming using D3.js v4

我有一个时间线图,其中包含指示特定事件的数据点。我试图在图表中构建缩放功能,但已走到尽头。我可以放大轴,但无法将数据点重新定位到新比例。我经历过许多 d3 bl.ocks 但没有找到解决方案。

我在 jsfiddle 中有一个最小版本: https://jsfiddle.net/q73ggw3e/2/

主要部分是:

缩放:

 var zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .translateExtent([[0, 0], [width, height]])
    .extent([[0, 0], [width, height]])
    .on("zoom", zoomed);

数据点:

svg.append("g")
   .selectAll("logo")
   .attr("class", "logo")
   .data(data)
   .enter()
   .append("circle")
   .attr("cy", 40)
   .attr("cx", function(d) { return x(d);})
   .attr("r", 10)
   .style("fill", "#000000")

缩放区域:

svg.append("rect")
   .attr("class", "zoom")
   .attr("width", width)
   .attr("height", height)
   .call(zoom);

以及缩放功能:

function zoomed() {
    svg.select(".axis--x")
       .call(xAxis.scale(d3.event.transform.rescaleX(x)));
    var new_x = d3.event.transform.rescaleX(x);
        svg.selectAll(".logo")
           .attr("cx", function(d) { return new_x(d);});
     };

我也应该将圆圈的 (.logo) class 绑定到缩放事件,但由于某些原因只有轴缩放...

我哪里错了?或者是否有一些完全不同的方式来做到这一点...

如果重要的话,数据点也将具有拖放、鼠标悬停和单击功能。这些目前工作正常,但缩放矩形会阻止指针事件。但这是在缩放工作后进行排序...

你做的图表很奇怪

            var margin = {
                top: 30,
                right: 20,
                bottom: 30,
                left: 120
              },
              width = 800 - margin.left - margin.right,
              height = 210 - margin.top - margin.bottom;


            var svg = d3.select(".zoom")
              .append("svg")
              .attr("width", width + margin.left + margin.right)
              .attr("height", height + margin.top + margin.bottom)
              .append("g")
              .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

            var y = d3.scaleLinear()
              .rangeRound([height, 0]);

            var x = d3.scaleTime()
              .rangeRound([0, width]);

            var xAxis = d3.axisTop(x)

            var zoom = d3.zoom()
                .scaleExtent([1, Infinity])
                .translateExtent([[0, 0], [width, height]])
                .extent([[0, 0], [width, height]])
                .on("zoom", zoomed);

            var parseTime = d3.timeParse("%Y-%m-%d");

            var lanes = ["A", "B", "C"]
            var lanesLength = lanes.length

            var a = ["2010-02-12", "2013-08-15", "2015-01-23", "2017-01-22"]
            var data = [];
            a.forEach(function (d){
                data.push(parseTime(d));
            });

            var today = new Date();
            x.domain([d3.min(data, function(d) { return d;}), today]);
            y.domain([0, lanesLength]);

            svg.append("g")
              .attr("class", "axis axis--x")
              .style("stroke-width", 2)
              .attr("transform", "translate(0)")
              .call(xAxis);


            svg.append("g")
              .selectAll(".lanetext")
              .data(lanes)
              .enter()
              .append("text")
              .text(function(d) { return d;})
              .attr("x", -margin.right)
              .attr("y", function(d, i) { return y(i + .5);})
              .attr("dy", ".5ex")
              .attr("text-anchor", "end")
              .attr("class", "lanetext")

            svg.append("g")
              
              .attr("class", "logomu")
              .selectAll("logomu")
              .data(data)
              .enter()
              .append("circle")
              .attr("cy", 40)
              .attr("class", "logo")
              .attr("cx", function(d) { return x(d);})
             .attr("r", 10)
             .style("fill", "#000000")

            svg.append("rect")
              .attr("class", "zoom")
              .attr("width", width)
              .attr("height", height)
              .call(zoom);

            function zoomed() {
                svg.select(".axis--x")
                    .call(xAxis.scale(d3.event.transform.rescaleX(x)));
                var new_x = d3.event.transform.rescaleX(x);
                svg.selectAll(".logo")
                    .attr("cx", function(d) { return new_x(d);});
            };
        .axis line{
            stroke: #000
        }
        .axis path{
            stroke: #000
        }
        .axis text{
            fill: #000
        }
        .lanetext {
            fill: #000
        }
        .zoom {
            cursor: move;
            fill: none;
            pointer-events: all;
            }
        .logo {
            fill: #000;
        }
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>

<body>

<div class="zoom">
</div>
</body>

I should be binding the (.logo) class of circles to the zoom event too, but for some reason only the axis zooms...

是否有class名称标识?检查 html 确保你附加它正确

Where am I going wrong? Or is there some completely other way of doing this...

你没有检查你画的是什么。是的,只需要经验