簡體   English   中英

在 D3js 中使用縮放/平移添加多個 y 軸

[英]Adding several y axes with zoom / pan in D3js

我正在 d3js 中處理一個水平折線圖,它根據 json 輸入顯示多條線。 它具有縮放和平移功能,但還需要為每條繪制的線顯示一個 y 軸。 就我而言,三個。

首先,這是不好的做法嗎? 我應該將所有三個堆疊在一側,還是應該將兩個放在左側,一個在右側或任何其他組合?

我試過遵循本教程,但這確實只會造成更多混亂和混亂的代碼。

我希望有人可以指導我如何添加額外的 y 軸以及我如何讓它們與縮放和平移一起工作,就像我現在擁有的那樣。

這是我目前的看法:在此處輸入圖片說明

這是我的代碼:

 <script>

        var margin = { top: 20, right: 80, bottom: 20, left: 40 },
            width = ($("#trendcontainer").width() - 50) - margin.left - margin.right,
            height = 650 - margin.top - margin.bottom;

        var svg;

        var format = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
        var x = d3.time.scale()
            .range([0, width]);

        var y0 = d3.scale.linear()
            .range([height, 0]);

        var y1 = d3.scale.linear()
            .range([height, 0]);

        var color = d3.scale.category10();
        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickSize(-height);
        // TODO: Rename axis to instrument name (i.e 'depth')
        var yAxis0 = d3.svg.axis()
            .scale(y0)
            .orient("left")
            .tickSize(-width);

        var yAxis1 = d3.svg.axis()
            .scale(y1)
            .orient("right")
            .tickSize(-width);

        var line = d3.svg.line()
            .interpolate("basis")
            .x(function(d) {
                return x(d.date);
            })
            .y(function(d) {
                return y0(d.value);
            });

        d3.json('@Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = Request.Params["runId"]})', function(error, tmparray) {
            var json = JSON.parse(tmparray);

            $('#processing').hide();

            color.domain(d3.keys(json[0]).filter(function(key) {
                return key !== "Time" && key !== "Id";
            }));

            json.forEach(function(d) {
                var date = format(d.Time);
                d.Time = date;
            });

            var instruments = color.domain().map(function(name) {
                return {
                    name: name,
                    values: json.map(function(d) {
                        return {
                            date: d.Time,
                            value: +d[name]
                        };
                    })
                };
            });

            x.domain(d3.extent(json, function(d) {
                return d.Time;
            }));
            y0.domain([
                d3.min(instruments, function (c) {
                    if (c.name == "Depth") {
                        return d3.min(c.values, function (v) {
                            return v.value;
                        });
                    }
                    //return d3.min(c.values, function (v) {
                    //    return v.value;
                    //});
                }),
                d3.max(instruments, function(c) {
                    return d3.max(c.values, function(v) {
                        return v.value;
                    });
                })
            ]);

            y1.domain([
                d3.min(instruments, function (c) {
                    console.log("In y1.domain c is: " + c);
                    if (c.name == "Weight") {
                        return d3.min(c.values, function (v) {
                            return v.value;
                        });
                    }
                    //return d3.min(c.values, function (v) {
                    //    return v.value;
                    //});
                }),
                d3.max(instruments, function(c) {
                    return d3.max(c.values, function(v) {
                        return v.value;
                    });
                })
            ]);

            var zoom = d3.behavior.zoom()
                .x(x)
                .y(y0)
                .scaleExtent([1, 10])
                .on("zoom", zoomed);

            svg = d3.select(".panel-body").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 + ")")
                .call(zoom)
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom);

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

            svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);

            svg.append("g")
                .attr("class", "y axis")
                .call(yAxis0);

            svg.append("g")
                .attr("class", "y axis")
                .call(yAxis1);

            var instrument = svg.selectAll(".instrument")
                .data(instruments)
                .enter().append("g")
                .attr("class", "instrument");

            instrument.append("path")
                .attr("class", "line")
                .attr("d", function(d) {
                    return line(d.values);
                })
                .style("stroke", function(d) {
                    return color(d.name);
                });

            instrument.append("text")
                .datum(function(d) {
                    return {
                        name: d.name,
                        value: d.values[d.values.length - 1]
                    };
                })
                .attr("transform", function(d) {
                    return "translate(" + x(d.value.date) + "," + y0(d.value.value) + ")";
                })
                .attr("x", 3)
                .attr("dy", ".35em")
                .text(function(d) {
                    return d.name;
                });
        });

        function zoomed() {
            svg.select(".x.axis").call(xAxis);
            svg.select(".y.axis").call(yAxis0);
            svg.select(".x.grid")
                .call(make_x_axis()
                    .tickSize(-height, 0, 0)
                    .tickFormat(""));
            svg.select(".y.grid")
                .call(make_y_axis()
                    .tickSize(-width, 0, 0)
                    .tickFormat(""));
            svg.selectAll(".line")
                .attr("d", function(d) { return line(d.values); });
        };

        var make_x_axis = function() {
            return d3.svg.axis()
                .scale(x)
                .orient("bottom")
                .ticks(5);
        };

        var make_y_axis = function() {
            return d3.svg.axis()
                .scale(y0)
                .orient("left")
                .ticks(5);
        };
</script>

最后,這就是我想要實現的目標(這個組件太慢了,不能很好地處理大型數據集):在此處輸入圖片說明

在@LarsKotthoff 的一些幫助下,最終得到了解決方案。 還添加了多軸縮放,基於這篇文章

<script>
    /* d3 vars */
    var x;
    var y1;
    var y2;
    var y3;
    var graph;
    var m = [];
    var w;
    var h;

    /* d3 axes */
    var xAxis;
    var yAxisLeft;
    var yAxisLeftLeft;
    var yAxisRight;

    /* d3 lines */
    var line1;
    var line2;
    var line3;

    /* d3 zoom */
    var zoom;
    var zoomLeftLeft;
    var zoomRight;                           

    /* Data */
    var speed = [];
    var depth = [];
    var weight = [];
    var timestamp = [];

    var url = '@Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = Request.Params["runId"]})';
    var data = $.getJSON(url, null, function(data) {
        var list = JSON.parse(data);
        var format = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
        list.forEach(function(d) {
            speed.push(d.Speed);
            depth.push(d.Depth);
            weight.push(d.Weight);
            var date = format(d.Time);
            d.Time = date;
            timestamp.push(d.Time);
        });

        m = [10, 80, 30, 100]; // margins: top, right, bottom, left
        w = $("#trendcontainer").width() - m[1] - m[3]; // width
        h = 550 - m[0] - m[2]; // height

        x = d3.time.scale().domain(d3.extent(timestamp, function (d) {
            return d;
        })).range([0, w]);

        y1 = d3.scale.linear().domain([0, d3.max(speed)]).range([h, 0]);
        y2 = d3.scale.linear().domain([0, d3.max(depth)]).range([h, 0]);
        y3 = d3.scale.linear().domain([0, d3.max(weight)]).range([h, 0]);

        line1 = d3.svg.line()
            .interpolate("basis")
            .x(function (d, i) {
                return x(timestamp[i]);
            })
            .y(function (d) {
                return y1(d);
            });

        line2 = d3.svg.line()
            .interpolate("basis")
            .x(function (d, i) {
                return x(timestamp[i]);
            })
            .y(function (d) {
                return y2(d);
            });

        line3 = d3.svg.line()
            .interpolate("basis")
            .x(function (d, i) {
                return x(timestamp[i]);
            })
            .y(function (d) {
                return y3(d);
            });

        zoom = d3.behavior.zoom()
            .x(x)
            .y(y1)
            .scaleExtent([1, 10])
            .on("zoom", zoomed);

        zoomLeftLeft = d3.behavior.zoom()
            .x(x)
            .y(y3)
            .scaleExtent([1, 10]);

        zoomRight = d3.behavior.zoom()
            .x(x)
            .y(y2)
            .scaleExtent([1, 10]);

        // Add an SVG element with the desired dimensions and margin.
        graph = d3.select(".panel-body").append("svg:svg")
            .attr("width", w + m[1] + m[3])
            .attr("height", h + m[0] + m[2])
            .call(zoom)
            .append("svg:g")
            .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

        // create xAxis
        xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(false);
        // Add the x-axis.
        graph.append("svg:g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + h + ")")
            .call(xAxis);

        // create left yAxis
        yAxisLeft = d3.svg.axis().scale(y1).ticks(10).orient("left");
        // Add the y-axis to the left
        graph.append("svg:g")
            .attr("class", "y axis axisLeft")
            .attr("transform", "translate(-15,0)")
            .call(yAxisLeft);

        // create leftleft yAxis
        yAxisLeftLeft = d3.svg.axis().scale(y3).ticks(10).orient("left");
        // Add the y-axis to the left
        graph.append("svg:g")
            .attr("class", "y axis axisLeftLeft")
            .attr("transform", "translate(-50,0)")
            .call(yAxisLeftLeft);

        // create right yAxis
        yAxisRight = d3.svg.axis().scale(y2).ticks(10).orient("right");
        // Add the y-axis to the right
        graph.append("svg:g")
            .attr("class", "y axis axisRight")
            .attr("transform", "translate(" + (w + 15) + ",0)")
            .call(yAxisRight);

        // add lines
        // do this AFTER the axes above so that the line is above the tick-lines
        graph.append("svg:path").attr("d", line1(speed)).attr("class", "y1");
        graph.append("svg:path").attr("d", line2(depth)).attr("class", "y2");
        graph.append("svg:path").attr("d", line3(weight)).attr("class", "y3");
    });

    function zoomed() {
        zoomRight.scale(zoom.scale()).translate(zoom.translate());
        zoomLeftLeft.scale(zoom.scale()).translate(zoom.translate());

        graph.select(".x.axis").call(xAxis);
        graph.select(".y.axisLeft").call(yAxisLeft);
        graph.select(".y.axisLeftLeft").call(yAxisLeftLeft);
        graph.select(".y.axisRight").call(yAxisRight);
        graph.select(".x.grid")
            .call(make_x_axis()
            .tickFormat(""));
        graph.select(".y.axis")
            .call(make_y_axis()
                .tickSize(5, 0, 0));
        graph.selectAll(".y1")
            .attr("d", line1(speed));
        graph.selectAll(".y2")
            .attr("d", line2(depth));
        graph.selectAll(".y3")
            .attr("d", line3(weight));
    };

    var make_x_axis = function () {
        return d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .ticks(5);
    };

    var make_y_axis = function () {
        return d3.svg.axis()
            .scale(y1)
            .orient("left")
            .ticks(5);
    };
</script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM