Question

I've ran into a problem with nvd3 where I'm getting a properly rendered line chart, but the interactive guideline doesn't seem to be working properly. At present when it is rendered and I move my mouse over the chart it only displays for the first date and last date. Any help would be greatly appreciated.

Code:

<script src="forecast/static/nvd3/lib/d3.v3.js"></script>
<script src="forecast/static/nvd3/nv.d3.js"></script>
<script src="forecast/static/nvd3/src/core.js"></script>
<script src="forecast/static/nvd3/src/tooltip.js"></script>
<script src="forecast/static/nvd3/src/utils.js"></script>
<script src="forecast/static/nvd3/src/interactiveLayer.js"></script>
<script src="forecast/static/nvd3/src/models/legend.js"></script>
<script src="forecast/static/nvd3/src/models/axis.js"></script>
<script src="forecast/static/nvd3/src/models/scatter.js"></script>
<script src="forecast/static/nvd3/src/models/line.js"></script>
<script src="forecast/static/nvd3/src/models/lineChart.js"></script>
<link type="text/css" rel="stylesheet" href="forecast/static/nvd3/nv.d3.css" />

<title>Foreign Exchange</title>

<body>
<h1>Foreign Exchange</h1>

<div id="chartZoom">
    <a href="#" id="zoomIn">Zoom In</a> <a href="#" id="zoomOut">Zoom Out</a>
</div>

<div id="fx" class='with-transitions'>
    <svg></svg>
</div>

</body>
<script type="text/javascript">
nv.addGraph(function() {
var chart = nv.models.lineChart();
var fitScreen = false;
var width = 600;
var height = 300;
var zoom = 1;

chart.useInteractiveGuideline(true);
chart.xAxis
    .axisLabel('Time (days)')
    .rotateLabels(-45)
    .tickFormat(function(d) { return d3.time.format('%b %d')(new Date(d)); });

chart.yAxis
    .axisLabel('CAD/USD ($)')
    .tickFormat(d3.format(',.2f'));

d3.select('#fx svg')
    .attr('perserveAspectRatio', 'xMinYMid')
    .attr('width', width)
    .attr('height', height)
    .datum(data());

setChartViewBox();
resizeChart();

// These resizes both do the same thing, and require recalculating the chart
//nv.utils.windowResize(chart.update);
//nv.utils.windowResize(function() { d3.select('#fx svg').call(chart) });
nv.utils.windowResize(resizeChart);

d3.select('#zoomIn').on('click', zoomIn);
d3.select('#zoomOut').on('click', zoomOut);


function setChartViewBox() {
    var w = width * zoom,
        h = height * zoom;

    chart
        .width(w)
        .height(h);

    d3.select('#fx svg')
        .attr('viewBox', '0 0 ' + w + ' ' + h)
        .transition().duration(500)
        .call(chart);
}

function zoomOut() {
    zoom += .25;
    setChartViewBox();
}

function zoomIn() {
    if (zoom <= .5) return;
    zoom -= .25;
    setChartViewBox();
}

// This resize simply sets the SVG's dimensions, without a need to recall the chart code
// Resizing because of the viewbox and perserveAspectRatio settings
// This scales the interior of the chart unlike the above
function resizeChart() {
    var container = d3.select('#fx');
    var svg = container.select('svg');

    if (fitScreen) {
        // resize based on container's width AND HEIGHT
        var windowSize = nv.utils.windowSize();
        svg.attr("width", windowSize.width);
        svg.attr("height", windowSize.height);
    } else {
        // resize based on container's width
        var aspect = chart.width() / chart.height();
        var targetWidth = parseInt(container.style('width'));
        svg.attr("width", targetWidth);
        svg.attr("height", Math.round(targetWidth / aspect));
    }
};

return chart;
});

function data() {
var x_data = [1394002800000, 1393916400000, 1393830000000, 1393570800000, 1393484400000, 1393398000000, 1393311600000, 1393225200000, 1392966000000, 1392879600000, 1392793200000, 1392706800000, 1392361200000, 1392274800000, 1392188400000, 1392102000000, 1392015600000, 1391756400000, 1391670000000, 1391583600000, 1391497200000, 1391410800000, 1391151600000, 1391065200000, 1390978800000, 1390892400000, 1390806000000, 1390546800000, 1390460400000, 1390374000000, 1390287600000, 1390201200000, 1389942000000, 1389855600000, 1389769200000, 1389682800000, 1389596400000, 1389337200000, 1389250800000, 1389164400000, 1389078000000, 1388991600000, 1388732400000, 1388646000000, 1388473200000, 1388386800000, 1388127600000, 1387868400000, 1387782000000, 1387522800000, 1387436400000, 1387350000000, 1387263600000, 1387177200000, 1386918000000, 1386831600000, 1386745200000, 1386658800000, 1386572400000, 1386313200000, 1386226800000, 1386140400000, 1386054000000, 1385967600000, 1385708400000, 1385622000000, 1385535600000, 1385449200000, 1385362800000];
var y_data = [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.91, 0.91, 0.91, 0.91, 0.91, 0.91, 0.91, 0.91, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.91, 0.91, 0.91, 0.92, 0.91, 0.91, 0.92, 0.92, 0.92, 0.93, 0.93, 0.94, 0.94, 0.94, 0.94, 0.94, 0.93, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.95, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.93, 0.94, 0.94, 0.94, 0.94, 0.94, 0.95, 0.95];
var data = [];
for(var i=0, len=x_data.length; i < len; i++){
    data.push({x: new Date(x_data[i]), y: y_data[i]});
}

return [
    {
        values: data,
        key: 'USD/CAD Exchange Rate',
        color: '#08c'
    }
];
}
</script>
Was it helpful?

Solution

It seems that NVD3 requires your x axis data to be sorted from earliest to latest, not the other way around as in yours. If I reverse the data, everything works fine -- just .reverse() both of your data arrays.

Complete example here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top