Re:尝试在D3.js中的多轴线图中拖动折线图

时间:2014-09-24 22:08:44

标签: javascript jquery svg d3.js graph

我最近开始研究d3.js.我正在开发具有双x轴的交互式多线图。请看看我的工作,JSFiDDLE:http://jsfiddle.net/dalapati/88bsax53/2/



            data1 = [{
                "date": 1357717800000,
                "value": "5.6"
            }, {
                "date": 1357718400000,
                "value": "5.6"
            }, {
                "date": 1357719000000,
                "value": "6"
            }, {
                "date": 1357719600000,
                "value": "5.1"
            }, {
                "date": 1357720200000,
                "value": "5.3"
            },
            //{"date": 1357720800000,"value": "5.4"}
            ];

            data2 = [{
                "date": 1357714800000,
                "value": "5.2"
            }, {
                "date": 1357715400000,
                "value": "5.2"
            }, {
                "date": 1357716000000,
                "value": "5.2"
            }, {
                "date": 1357716600000,
                "value": "5.1"
            }, {
                "date": 1357717200000,
                "value": "5.5"
            }, ]

            // date manipulation to format UTC to js Date obj           
            data1.forEach(function (d) {
                d.time = new Date(d.time * 1000);
            });
            data2.forEach(function (d) {
                d.time = new Date(d.time * 1000);
            });

            // helpers and constants        
            var margin = {
                "top": 50,
                "right": 50,
                "bottom": 50,
                "left": 100,
                "axis": 55
            };
            var width = 800 - margin.left - margin.right;
            var height = 580 - margin.top - margin.bottom;
            var timeFormat = d3.time.format("%X");

            // find data range
            var x1Domain = d3.extent(data1, function (d) {
                return d.date;
            });
            var x2Domain = d3.extent(data2, function (d) {
                return d.date;
            });

            var x1Min = d3.min(data1, function (d) {
                return Math.min(d.date);
            });
            var x1Max = d3.max(data1, function (d) {
                return Math.max(d.date);
            });

            var x2Min = d3.min(data2, function (d) {
                return Math.min(d.date);
            });
            var x2Max = d3.max(data2, function (d) {
                return Math.max(d.date);
            });

            var y1Min = d3.min(data1, function (d) {
                return Math.min(d.value);
            });
            var y1Max = d3.max(data1, function (d) {
                return Math.max(d.value);
            });

            var y2Min = d3.min(data2, function (d) {
                return Math.min(d.value);
            });
            var y2Max = d3.max(data2, function (d) {
                return Math.max(d.value);
            });

            var yMin = (y1Min < y2Min) ? y1Min : y2Min;
            var yMax = (y1Max > y2Max) ? y1Max : y2Max;

            // scales
            var x1Scale = d3.time.scale()
                .domain(d3.extent(data1, function (d) {
                return d.date;
            }))
                .range([0, width]);
            var x2Scale = d3.time.scale()
                .domain(d3.extent(data2, function (d) {
                return d.date;
            }))
                .range([0, width]);
            var yScale = d3.scale.linear()
                .domain([yMin, yMax]).range([height, 0]);

            // set up axes
            var x1Axis = d3.svg.axis()
                .scale(x1Scale)
                .orient("bottom")
                .ticks(5)
                .tickPadding(5)
                .tickFormat(timeFormat);
            var x2Axis = d3.svg.axis()
                .scale(x2Scale)
                .orient("top")
                .ticks(5)
                .tickPadding(5)
                .tickFormat(timeFormat);
            var yAxis = d3.svg.axis()
                .scale(yScale)
                .orient("left")
                .ticks(5);
            var make_y_axis = function () {
                return d3.svg.axis()
                    .scale(yScale)
                    .orient("left")
                    .ticks(5);
            };

            // Set up chart type
            // create a line function that can convert data into x and y points
            var line1 = d3.svg.line().interpolate("basis")
                .x(function (d) {
                return x1Scale(d.date);
            })
                .y(function (d) {
                return yScale(d.value);
            });
            var line2 = d3.svg.line().interpolate("basis")
                .x(function (d) {
                return x2Scale(d.date);
            })
                .y(function (d) {
                return yScale(d.value);
            });
            
            // Create Drag behaviour
            var drag = d3.behavior.drag()
                .origin(function (d) {
                return d;
            })
                .on("drag", dragmove);


            // create svg container
            var svg = d3.select('#chart')
                .append("svg:svg")
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
                .append("svg:g")
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

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

            //Draw Axes
            svg.append("svg:g")
                .attr("class", "x axis axisBottom")
                .attr("transform", "translate(0, " + height + ")")
                .call(x1Axis);

            svg.append("svg:g")
                .attr("class", "x axis axisTop")
                .attr("transform", "translate(0, 0)")
                .call(x2Axis);

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

            // grid plot
            svg.append("g")
                .attr("class", "y grid")
                .call(make_y_axis()
                .tickSize(-width, 0, 0)
                .tickFormat(""));

            // add lines
            // do this AFTER the axes above so that the line is above the tick-lines
            var clip = svg.append("svg:clipPath")
                .attr("id", "clip")
                .append("svg:rect")
                .attr("x1Scale", 0)
                .attr("x2Scale", 0)
                .attr("yScale", 0)
                .attr("width", width)
                .attr("height", height);

            var chartBody = svg.append("g")
                .attr("clip-path", "url(#clip)");

            chartBody.append("svg:path")
                .datum(data1)
                .attr("class", "data1")
                .attr("d", line1(data1));

            chartBody.append("svg:path")
                .datum(data2)
                .attr("class", "data2")
                .attr("d", line2(data2));

            /************************** ADDING CROSS HAIRS *******************************************/
            // Add cross hairs and floating value on axis
            var crossHair = svg.append("g")
                .attr("id", "crosshair");
            //vertical crosshair
            crossHair.append("line").attr("id", "v_crosshair")
                .attr("x1", 0)
                .attr("y1", -height)
                .attr("x2", 0)
                .attr("y2", height)
            //text label for cross hair
            var crossHairTextData1 = svg.append("g")
                .attr("id", "crosshair_text");
            crossHairTextData1.append("text")
                .style("background", "white");

            var crossHairTextData2 = svg.append("g")
                .attr("id", "crosshair_text");
            crossHairTextData2.append("text")

             var crossHairTextValue = svg.append("g")
                .attr("id", "crosshair_text");
            crossHairTextValue.append("text")

             svg.on("mousemove", function () {
                var xCoord = d3.mouse(this)[0],
                    yCoord = d3.mouse(this)[1];
                addCrossHair(xCoord, yCoord);
            })
                .on("mouseover", function () {
                d3.selectAll(".crosshair").style("display", null);
            })
                .on("mouseout", function () {
                d3.selectAll(".crosshair").style("display", "none");
            })
                .append("rect")
                .style('visibility', 'hidden')
                .attr('x', 0)
                .attr('y', 0)
                .attr('width', width)
                .attr('height', height);

            function addCrossHair(xCoord, yCoord) {
                // Update horizontal cross hair
                d3.select("#h_crosshair")
                    .attr("x1", x1Scale(x1Min))
                    .attr("y1", yCoord)
                    .attr("x2", x1Scale(x1Max))
                    .attr("y2", yCoord)
                    .style("display", "block");
                // Update vertical cross hair
                d3.select("#v_crosshair")
                    .attr("x1", xCoord)
                    .attr("y1", yScale(yMin))
                    .attr("x2", xCoord)
                    .attr("y2", yScale(yMax))
                    .style("display", "block");

                // Update text label
                crossHairTextData1.select("text")
                    .attr("transform", "translate(" + (xCoord) + "," + (height - 10) + ")")
                    .text("(" + x1Scale.invert(xCoord) + ")");

                crossHairTextData2.select("text")
                    .attr("transform", "translate(" + (xCoord) + ", 15)")
                    .text("(" + x2Scale.invert(xCoord) + ")");

                crossHairTextValue.select("text")
                    .attr("transform", "translate(" + (xCoord + 5) + "," + (yCoord - 5) + ")")
                    .text("(" + yScale.invert(yCoord) + ")");

            }

            /*********************** Adding Dragging feature****************************/

            d3.select(".data1")
                .attr("cursor", "move")
                .call(drag);

            function dragmove(d) {
                var lineToMove = d3.event.x;
                d3.select(this)
                    .transition()
                    .duration(500)
                    .ease("linear")
                    .attr("transform", function () {
                    return "translate(" + lineToMove + ")";
                });
            }
&#13;
    text{
    	fill: black;
    	font-family: 'Ubuntu', 'Helvetica', 'Arial', sans-serif !important;
    }

    path {
    	stroke-width: 3px;
    	fill: none;
    }

    .line{
    	fill: none;
    	stroke: #0CD1AA;
    	stroke-width: 3px;
    }



    .data1, .line1{
    	stroke: #0CD1AA;
    }

    .data2, .line2{
    	stroke: orange;
    }

    .plot{
    	fill: #c9c9c9; /*Gray*/
    	opacity: 0.5;
    }

    .horizontalGrid{
    	fill: none;
    	shape-rendering: crispEdges;
    	stroke: grey;
    	stroke-width: 1px;
    	stroke-dasharray: 6,3;
    	opacity: 0.33;
    }

    .grid .tick{
    	fill: none;
    	shape-rendering: crispEdges;
    	stroke: grey;
    	stroke-width: 1px;
    	stroke-dasharray: 6,3;
    	opacity: 0.33;
    }

    .grid path{
    	stoke-width: 0;
    }

    .axis path,
    .axis line {
    	fill: none;
    	stroke: #000;
    	shape-rendering: crispEdges;
    }

    .x.axis path{
    	display: none;
    }

    .x.axisBottom text{
    	fill: #0CD1AA ;
    }

    .x.axisTop text{
    	fill: orange ;
    }

    /*
    .area{
    	fill: url(#temperature-gradient);
    	opacity: 0.6;
    }
    */

    .overlay {
      fill: none;
      pointer-events: all;
      cursor: none;
    }

    .focus line {
      fill: none;
      stroke: black;
    }

    #h_crosshair, #v_crosshair{
    	stroke: gray;
    	stroke-width: 1px;
    	stoke-dasharray:5,5;
    	display: none;
    }
    #crosshair_text{
    	font-size: 12px;
    	color: black;
    	stroke-width: 0.5px;
    	background-color: white;
    	opacity: 0.7;
    }
&#13;
    <!doctype html>
    <html>
    <head>
        <title> D3 Chart </title>
        <link rel="stylesheet" type="text/css" href="base.css">
        <script src="http://d3js.org/d3.v3.min.js"> </script>
        <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    	<meta content="utf-8" http-equiv="encoding">
    </head>

    <body>

        <div id="chart"></div>

    </body>

    </html>
&#13;
&#13;
&#13;

如您所见,有两个不同的折线图,取自不同的数据源并相对于两个不同的x轴绘制。我试图将拖动行为实现到每个线图,使得相应的轴也应该与图一起移动。

以一种简单的方式,当我选择一个图形并拖动它并保持另一个图形不变时,相应的轴值也应该更新。任何人都可以帮助我完成这项任务。

0 个答案:

没有答案