2014-09-25 102 views
0

我最近开始在D3.js上工作。我正在开发具有双x轴的交互式多线图。请看看我的工作,是的jsfiddle这里:http://jsfiddle.net/dalapati/cdkn14j3/1/D3.js - 如何解决NAN错误,同时拖动线图(Jsfiddle提供)

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 = 1500 - 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 Zoom feature 
var zoomBottom = d3.behavior.zoom() 
        .x(x1Scale) 
        //.y(yScale); 
        .scaleExtent([1,10]); 
var zoom = d3.behavior.zoom() 
        .x(x2Scale) 
        //.y(yScale) 
        .scaleExtent([1,10]) 
        .on("zoom",zoomed); 


// Create Drag behaviour 
var drag = d3.behavior.drag() 
      .origin(function(d){return d;}) 
      .on("dragstart", dragstarted) 
      .on("drag", dragged) 
      .on("dragend", dragended) 


// 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 + ")") 
       .call(zoom); 

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

function draw(){ 
//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)) 
     .attr("cursor", "move") 
     .call(drag); 

    chartBody.append("svg:path") 
     .datum(data2) 
     .attr("class", "data2") 
     .attr("d", line2(data2)) 
     .attr("cursor", "move") 
     .call(drag); 
    } 

    draw(); 
/************************** ADDING ZOOMING FEATURE****************************************/ 

function zoomed() { 
     //console.log(d3.event.translate); 
     //console.log(d3.event.scale);   
     zoomBottom.scale(zoom.scale()).translate(zoom.translate()); 
     svg.select(".axisBottom").call(x1Axis); 
     svg.select(".axisTop").call(x2Axis); 
     svg.select(".y .axis").call(yAxis); 
     svg.select(".grid").call(make_y_axis().tickSize(-width,0,0).tickFormat("")); 
     svg.select(".data1").attr("d",line1(data1)); 
     svg.select(".data2").attr("d",line2(data2)); 
    } 

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

function dragstarted(d){ 
    d3.event.sourceEvent.stopPropagation(); 
    d3.select(this).classed("dragging", true); 
} 

function dragged(d){ 
    var lineToMove = d3.event.x; 
    console.log(lineToMove); 
    d3.select(this) 
     .attr("cx", d[0] = d3.event.sourceEvent.x); 
} 

function dragended(d){ 
    d3.select(this).classed("dragging", false); 
} 

正如你看到的,有两个不同的线图,从不同的数据源,并采取绘制相对于两个不同的x轴。我试图对每个线图实现拖动行为,其中如果我选择一个图并拖动它并保持另一个图不变,则相应的轴值也应该更新。

但是,当我尝试拖动折线图时,出现NAN错误。我不知道如何解决这个错误。有没有人有任何想法我错了。

在此先感谢。

回答

2

问题是当你设置原点时,因为它期望一个x和y的对象。

尝试:

.origin(function(){ var t = d3.select(this); return { x: t.attr('x') , y: t.attr('y') } }) 

参考How to set the Origin (drag.origin) for drag behavior in d3 JavaScript library

+0

嗨布鲁诺·奎罗斯,谢谢你的回复。我很感谢你的回答。我尝试了你发布的代码片段。 NaN错误问题已解决,但仍然在我尝试拖动图形时未更新值。还有什么可以建议我实现图形中的拖动行为?这是更新的Jsfiddle:http://jsfiddle.net/dalapati/cdkn14j3/2/。谢谢! – Dinesh 2014-09-25 23:18:21

+0

实际上,如果您打开控制台并开始拖动一条线,您将看到lineToMove的值正在更改,但该代码中的任何位置未使用此变量 – 2014-09-25 23:43:02

+0

已创建“lineTOMove”变量以查看安慰。但它被分配给属性“cx”。好的,在我发布的代码中,我没有更新lineToMove变量,它等于“d3.event.sourceEvent.x”。我想这不会导致错误。我的理解是,最初当我缩放图形时,缩放功能按预期工作。后来,当我试图拖动任何一个线图时,拖动功能不起作用,但是从控制台我可以看到事件值正在更新。我不确定这里有什么问题。 – Dinesh 2014-09-26 00:02:05

相关问题