d3.js如何同时缩放多个图表

时间:2018-02-27 12:24:40

标签: javascript d3.js

我是d3.js的新手并试图在一页中绘制多个图表,这些图表在-x-轴上都有时间维度。 我希望在缩放页面中的任何图形时对所有图形应用相同的缩放。如何实现这一目标?您可以在此处找到一个可用的示例:Multiple Charts example,我需要在缩放事件功能中进行哪些更改?

 var zoom = d3.behavior.zoom()
    .scaleExtent([1, 20])
    .x(x)
    .on('zoom', function zoomHandler() {

        axes.select('.x-axis')
            .call(xAxis);

        circles.attr("transform", function (d) {
            return "translate(" + x(d.date) + "," + y(d.measurement) + ")";
        });

        svg.selectAll('path.line')
            .attr('d', function (d) {
                return line(d.values);
            });
    });

1 个答案:

答案 0 :(得分:2)

我找到了发布的jsfiddle的解决方案。我在图表函数外部定义了缩放行为,并将svg,circle,line和axes对象保存在相应的列表全局对象中,以便可以在图形创建范围之外访问。最后,我创建了一个setzoom函数,该函数在创建所有图形之后调用,并在svglist数组中进行迭代,并在svglist,circlelist和linelist中保存的每个对象中应用相同的转换。最终的JavaScript代码是:

     var timeFormat = d3.time.format('%Y-%m-%d %H:%M:%S');

    var customTimeFormat = d3.time.format.multi([
        [".%L", function (d) { return d.getMilliseconds(); }],
        [":%S", function (d) { return d.getSeconds(); }],
        ["%H:%M", function (d) { return d.getMinutes(); }],
        ["%H:%M", function (d) { return d.getHours(); }],
        ["%d / %m", function (d) { return d.getDay() && d.getDate() != 1; }],
        ["%d", function (d) { return d.getDate() != 1; }],
        ["%m - %Y", function (d) { return d.getMonth(); }],
        ["%Y", function () { return true; }]
    ]);

        var color = d3.scale.category10();

    var width = 900,
        height = 250,
        margin = {
            top: 5,
            right: 50,
            bottom: 20,
            left: 80
        };

    var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;

    var x = d3.time.scale().range([margin.left, width - margin.right]);




       var  xAxis = d3.svg.axis()
            .scale(x)
            .tickFormat(customTimeFormat)
            .innerTickSize(0)
            .outerTickSize(0)
            .orient("bottom");
   var zoom = d3.behavior.zoom();

    var circleslist=[];
    var svglist=[];
   var   axeslist=[];
   var ylist=[];
   var linelist=[];
   function setzoom()
   {

        zoom.scaleExtent([1, 20])
        .x(x)
        .on('zoom', function zoomHandler() {

        //alert(svglist.length);
        for(var i=0;i<3;i++)
        {
          axeslist[i].select('.x-axis')
                .call(xAxis);

            circleslist[i].attr("transform", function (d) {
                return "translate(" + x(d.date) + "," + ylist[i](d.measurement) + ")";
            });

            svglist[i].selectAll('path.line')
                .attr('d', function (d) {
                    return linelist[i](d.values);
                });

        }

        });

    }   


     var chartValuesList1 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
    { Date: "2018-01-29 12:47:09", Measurement: 225 },{ Date: "2018-01-29 13:47:13", Measurement: 224 },{ Date: "2018-01-29 14:47:13", Measurement: 225 },{ Date: "2018-01-29 15:47:10", Measurement: 223 },
    { Date: "2018-01-29 16:47:11", Measurement: 223 }];
    var Array1 = [{ name: "Plot1", units: "", chartValuesList:chartValuesList1 }];
     var chartValuesList2 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
    { Date: "2018-01-29 12:47:09", Measurement: 225 },{ Date: "2018-01-29 13:47:13", Measurement: 224 },{ Date: "2018-01-29 14:47:13", Measurement: 200 },{ Date: "2018-01-29 15:47:10", Measurement: 233 },
    { Date: "2018-01-29 16:47:11", Measurement: 240 }];
    var Array2 = [{ name: "Plot2", units: "", chartValuesList:chartValuesList2 }];
      var chartValuesList3 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
    { Date: "2018-01-29 12:47:09", Measurement: 550 },{ Date: "2018-01-29 13:47:13", Measurement: 600 },{ Date: "2018-01-29 14:47:13", Measurement: 400 },{ Date: "2018-01-29 15:47:10", Measurement: 300 },
    { Date: "2018-01-29 16:47:11", Measurement: 600 }];
    var Array3 = [{ name: "Plot3", units: "", chartValuesList:chartValuesList3 }]; 


    chart("chart1", Array1, "Values");
    chart("chart2", Array2, "Values");
    chart("chart3", Array3, "Values");

    setzoom();




    function chart(chartID, chartData, heading) {

        var y = d3.scale.linear().range([height - margin.bottom, margin.top]);
        ylist.push(y);

       var yAxis = d3.svg.axis()
        .scale(y)
        .tickFormat(function (d) { return d; })
        .innerTickSize(-(width - margin.left - margin.right))
        .outerTickSize(0)
        .orient("left");


    var data = chartData;






    var line = d3.svg.line()
        .interpolate("linear")
        .x(function (d) { return x(d.date); })
        .y(function (d) { return y(d.measurement); });
        linelist.push(line);

    var container = d3.select("#" + chartID);

    var svg = container.append("svg")
        .attr('width', width)
        .attr('height', height);
        svglist.push(svg);

    var defs = svg.append('defs');

    defs.append('clipPath')
        .attr('id', 'plot-area-clip-path')
        .append('rect')
        .attr({
            x: margin.left,
            y: margin.top,
            width: width - margin.right - margin.left,
            height: height - margin.top - margin.bottom
        });

    var backRect = svg.append('rect')
        .style('stroke', 'none')
        .style('fill', '#FFF')
        .style('fill-opacity', 0)
        .attr({
            x: margin.left,
            y: margin.top,
            width: width - margin.right - margin.left,
            height: height - margin.top - margin.bottom,
            'pointer-events': 'all'
        });

     axes = svg.append('g')
        .attr('pointer-events', 'none')
        .style('font-size', '11px');
    axeslist.push(axes);

    var chart = svg.append('g')
        .attr('class', 'plot-area')
        .attr('pointer-events', 'none')
        .attr('clip-path', 'url(#plot-area-clip-path)');

    var dates = [];
    var measurements = [];
    var dateStrings = [];

    var units;

    var chartLines = data.map(function (chartLine) {
        units = chartLine.units;
        return {
            name: chartLine.name,
            units: chartLine.units,
            values: chartLine.chartValuesList.map(function (value) {
                dateStrings.push(value.Date);
                var date = parseDate(value.Date);
                var measurement = value.Measurement;
                dates.push(date);
                measurements.push(measurement);
                return {
                    date: date,
                    measurement: measurement
                };
            })
        }
    });

    x.domain(d3.extent(dates));

    if (chartID == "charge-chart" || chartID == "genBattVdc-chart") {
        var max = d3.max(measurements);
        y.domain([0, max + (0.1 * max)]);
    }
    //        else if (chartID ==  "powerFact_g-chart") {
    //            y.domain([-1.2, 1.2]);
    //        }
    //energy-chart
    else if (chartID == "energy-chart") {
        y.domain(d3.extent(measurements));
    }

    else {
        //y.domain(d3.extent(measurements));
        y.domain([d3.min(measurements) - 0.01 * d3.min(measurements), 1.01 * d3.max(measurements)]);
    }


    var xAxisEl = axes.append('g')
        .attr('class', 'x-axis')
        .attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom) + ')')
        .call(xAxis);

    var yAxisEl = axes.append('g')
        .attr('class', 'y-axis')
        .attr('transform', 'translate(' + margin.left + ',' + 0 + ')')
        .call(yAxis);

    svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 20)
        .attr("x", -height / 2)
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text((units == "") ? "" : "( " + units + " )");


    backRect.call(zoom);

    yAxisEl.selectAll('line')
        .style('stroke', '#BBB')
        .style('stroke-width', '1px')
        .style('shape-rendering', 'crispEdges');

    var chartLine = chart.selectAll(".chartLine")
        .data(chartLines)
        .enter().append("g")
        .attr("class", "chartLine");

    var paths = chart.selectAll(".chartLine").append("g")
        .attr("class", "plot")
        .attr("id",
        function (d, i) {
            return 'tag' + d.name.replace(/\s+/g, '');
        })
        .append("path")
        .attr("class", "line")
        .attr("d", function (d) {
            return line(d.values);
        })
        .style("stroke", function (d, i) {
            return color(i);
        });

    /* Title and Legends */

    var chartInfo = container.append('svg')
        .attr("class", "title")
        .attr("x", width + 65)
        .attr("y", 50)
        .attr("height", height)
        .attr("width", 200);

    var title = chartInfo.append('svg')
        .attr("class", "title")
        .attr('width', 200)
        .attr('height', 40)
        .attr("x", 10)
        .attr("y", 0)
        .append('g')
        .append("text")
        .attr("x", 0)
        .attr("y", 30)
        .attr("height", 30)
        .attr("width", 200)
        .attr("text-anchor", "start")
        .style("font-size", "16px")
        .style("font-weight", "bold")
        .style("fill", "rgb(128,128,128)")
        .text(heading);

    var legends = chartInfo.append('svg')
        .attr("class", "legend")
        .attr('width', 200)
        .attr('height', height - 40)
        .attr("x", 10)
        .attr("y", 60);

    legends.selectAll('g').data(chartLines)
        .enter()
        .append('g')
        .each(function (d, i) {
            var g = d3.select(this);
            g.append("rect")
                .attr("x", 10)
                .attr("y", i * 25)
                .attr("width", 10)
                .attr("height", 10)
                .style("fill", color(i));

            g.append("text")
                .attr("x", 30)
                .attr("y", i * 25 + 10)
                .attr("height", 30)
                .attr("width", 100)
                .style("fill", color(i))
                .on("click", function () {
                    (!d.active) ? $(this).attr("opacity", 0.3) : $(this).attr("opacity", 1);
                    var active = d.active ? false : true,
                        newOpacity = active ? 0 : 1;
                    d3.select('#tag' + d.name.replace(/\s+/g, ''))
                        .transition().duration(100)
                        .style('opacity', newOpacity);
                    d.active = active;
                })
                .text(d.name);
        });

    /* Dots */

    var circles = chart.selectAll(".chartLine").select('.plot').append('g')
        .attr("class", "dots")
        .selectAll('circle')
        .data(function (d) { return d.values; })
        .enter().append('circle')

        //            .attr('cy', function(d){
        //                return y(d.measurement);
        //            })
        //            .attr('cx', function(d){
        //                return x(d.date);
        //            })
        .attr("transform", function (d) {
            return "translate(" + x(d.date) + "," + y(d.measurement) + ")";
        })

        .attr('r', 1)
        .attr('fill', 'black')
        .attr('pointer-events', 'all')
        .attr('stroke', 'black')
        .attr('stroke-width', 1)

        .on("mouseover", mouseover)
        .on("mousemove", function (d) {
            var aa = new Date(d.date);
            var h = aa.getHours();
            var m = aa.getMinutes();
            var s = aa.getSeconds();
            var t = h + ":" + m + ":" + s;
            console.log(aa, t)
            divToolTip.text(this.parentNode.__data__.units + ": " + d.measurement + ", " + "Time: " + t)

                .style("left", (d3.event.pageX + 15) + "px")
                .style("top", (d3.event.pageY - 10) + "px");
        })
        .on("mouseout", mouseout);

            circleslist.push(circles);

    /* Tooltip */

    var divToolTip = d3.select("body").append("div")
        .attr("class", "tooltip")
        .style("opacity", 1e-6);

    function mouseover() {
        divToolTip.transition()
            .duration(100)
            .style("opacity", 1);
    }

    function mouseout() {
        divToolTip.transition()
            .duration(100)
            .style("opacity", 1e-6);
    }


}