微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 D3 中将缩放和注释或选择功能结合在一起

如何解决如何在 D3 中将缩放和注释或选择功能结合在一起

我刚刚开始学习 D3 和 JavaScript。我正在尝试制作一个可缩放的流图,并且可以选择为用户指示特定的数据值。 所以我开始首先选择和显示数据点的注释,效果很好。然后我学会了如何缩放流图。但是当把它们放在一起时,我发现选择/注释功能不再起作用了。有人有什么建议吗?

这里有两张图片,一张显示 zoom function,另一张显示 annotation function

非常感谢!

(function () {
    // first,load the dataset from a CSV file


    d3.csv("https://raw.githubusercontent.com/FeisNowflakes/zoomtest222/main/streamgraph-test/Los_Angeles_International_Airport_-_Passenger_Traffic_By_Terminal.csv")

        .then(data => {
            // log csv in browser console
            console.log(data);

            var advanceVisData = {};
            var airport = new Set();


            data.forEach(d => {
                airport.add(d['Terminal']);
                var period = new Date(d['ReportPeriod']);
                if (period in advanceVisData) {
                    if (d['Terminal'] in advanceVisData[period]) {
                        advanceVisData[period][d['Terminal']] += Number(d['Passenger_Count']);
                    }
                    else {
                        advanceVisData[period][d['Terminal']] = Number(d['Passenger_Count']);
                    }
                }
                else {
                    advanceVisData[period] = {};
                    advanceVisData[period][d['Terminal']] = Number(d['Passenger_Count']);
                }
            });

            console.log(airport);
            console.log(advanceVisData);


            // reformat the advanceVisData for d3.stack()
            var formattedData = [];
            Object.keys(advanceVisData).forEach(d => {
                var item = {};
                item['year'] = d;
                airport.forEach(terminal => {
                    if (terminal in advanceVisData[d]) {
                        item[terminal] = advanceVisData[d][terminal];
                    } else {
                        item[terminal] = 0;
                    }
                });
                formattedData.push(item);
            });
            console.log(formattedData);


            /*********************************
             * Visualization codes start here
             * ********************************/

            var width = 1000;
            var height = 300;
            var margin = { left: 60,right: 20,top: 20,bottom: 60 };
            //set the dimensions and margins of the graph



            // append the svg object to the body of the page
            var svg = d3.select('#container')
                .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 + ")");

            // List of groups = header of the csv files
            var keys = Array.from(airport);

            //stack the data?
            var stackedData = d3.stack()
                //.offset(d3.stackOffsetSilhouette)
                .keys(keys)
                (formattedData);
            console.log(stackedData);
            var max_val = 0;
            var min_val = 0;
            stackedData.forEach(terminal => {
                terminal.forEach(year => {
                    if (year[0] < min_val) min_val = year[0];
                    if (year[1] < min_val) min_val = year[1];
                    if (year[0] > max_val) max_val = year[0];
                    if (year[1] > max_val) max_val = year[1];
                })
            });
            //console.log(max_val,min_val);

            // Add X axis

            var x = d3.scaleTime()
                .domain(d3.extent(formattedData,function (d) {
                    return new Date(d.year);
                }))
                .range([0,width]);


            var xAxis = svg.append("g")
                .attr("transform","translate(0," + height + ")")
                .call(d3.axisBottom(x).ticks(20));


            // Add Y axis
            var y = d3.scaleLinear()
                .domain([min_val,max_val])
                .range([height,0]);
            var yAxis = svg.append("g")
                .call(d3.axisLeft(y));

            // color palette
            var color = d3.scaleOrdinal()
                .domain(keys)
                .range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#f781bf',"#87sbf","#ff981bf","#d6a3b6",'#b3afb0','#ddd8c2']);


            // create a tooltip
            var Tooltip = svg
                .append("text")
                .attr("x",0)
                .attr("y",0)
                .style("opacity",0)
                .style("font-size",17)


            //Add a clipPath: everything out of this area won't be drawn.
            var clip = svg.append("defs").append("svg:clipPath")
                .attr("id","clip")
                .append("svg:rect")
                .attr("width",width)
                .attr("height",height)
                .attr("x",0);


            const itemmouSEOver = (selectedTerminal) => {
                d3.selectAll(".myStreamArea").style("opacity",.3);

                d3.selectAll(".myStreamArea")
                    .each(function (d) {
                        if (d.key === selectedTerminal) {
                            d3.select(this)
                                .style("stroke","black")
                                .style("opacity",1);
                        }
                    });
            };

            const itemmouseLeave = () => {
                d3.selectAll(".myStreamArea")
                    .style("opacity",1)
            };





            // Show the areas
            var stream = svg.append("g")
                .attr("clip-path","url(#clip)")

            stream
                .selectAll(".myStreamArea")
                .data(stackedData)
                .enter()
                .append("path")
                .attr("class","myStreamArea")
                .style("fill",function (d) {
                    return color(d.key);
                })
                .style("opacity",1)
                .attr("d",d3.area()
                    .x(function (d) {
                        return x(new Date(d.data.year));
                    })
                    .y0(function (d) {
                        return y(d[0]);
                    })
                    .y1(function (d) {
                        return y(d[1]);
                    })

                )
                .on("mouSEOver",function (d,i) {
                    itemmouSEOver(i.key);
                })
                .on("mousemove",i) {
                    var selectedDate = x.invert(d3.pointer(event,this)[0]);
                    var displayVal = null;
                    i.forEach(k => {
                        var tmpDate = new Date(k.data.year);
                        if (tmpDate.getFullYear() === selectedDate.getFullYear()
                            && tmpDate.getMonth() === selectedDate.getMonth()) {
                            displayVal = (k.data)[i.key];
                        }
                    });
                    console.log(displayVal);

                    d3.select('#mouse_move_text')
                        .remove();
                    svg.append("text")
                        .attr("id","mouse_move_text")
                        .attr("x",width / 2)
                        .attr("y",0)
                        .style("font-size","12px")
                        .attr("font-weight","bold")
                        .text("passenger count:" + displayVal)
                        ;
                })
                .on("mouseleave",i) {
                    d3.select('#mouse_over_text')
                        .remove();
                    itemmouseLeave();
                });


            // Set the zoom and Pan features: how much you can zoom,on which part,and what to do when there is a zoom
            var zoom = d3.zoom()
                .scaleExtent([1,9])  // This control how much you can unzoom (x0.5) and zoom (x20)
                .extent([[0,0],[width,height]])
                .on("zoom",updateChart);


            // This add an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
            svg.append("rect")
                .attr("width",height)
                .style("fill","none")
                .style("pointer-events","all")
                .call(zoom);

            // Now the user can zoom and it will trigger the function called updateChart

            // A function that updates the chart when the user zoom and thus new boundaries are available
            function updateChart() {

                // recover the new scale
                var transform = d3.zoomTransform(this);
                var newX = transform.rescaleX(x);


                // update axes with these new boundaries

                xAxis.call(d3.axisBottom(newX)); //.ticks(20)


                stream
                    .selectAll(".myStreamArea")
                    .attr("d",d3.area()
                        .x(function (d) {
                            return newX(new Date(d.data.year));
                        })
                        .y0(function (d) {
                            return y(d[0]);
                        })
                        .y1(function (d) {
                            return y(d[1]);
                        }));
                //);
            }



        })
})();
<!DOCTYPE html>
<html lang="en">
  <head>
    <Meta charset="utf-8">
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style>
      #tooltip {
        min-width: 100px;
        min-height: 50px;
        background-color: white;
      }
    </style>
  </head>
  <body>
    <div id="container"> <div id="tooltip"></div></div>
    <script src="selectzoom.js"></script>
    <!-- <script src="select.js"></script> -->
  </body>
</html>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。