Vinlinca
Vinlinca

Reputation: 23

d3.js Multi-line graph with zoom : line error

It is my version of "Multi-line graph 4: Toggle" from http://bl.ocks.org/d3noob/e99a762017060ce81c76 but I ran into some problems pls help.

At first the initial graph is correct,

I think it is the zoomed functions is not doing right, when I used "d.value" the browser would say "d. is not define"

Here are the codes:

// https://github.com/mbostock/d3/wiki/Ordinal-Scales#category10
var colors = d3.scale.category10(); 

var margin = {top: 20, right: 30, bottom: 80, left: 85},
    width = 900 - margin.left - margin.right,
    height = 570 - margin.top - margin.bottom;

// Kind of defining the length and the directions of the axis    
var x = d3.scale.linear()
    .range([0, width]); 

// Since the origin is on the left corner, the y axis of the svg system points down 
var y = d3.scale.linear()
    .range([height, 0]); 
    
var xAxis = d3.svg.axis()
    .scale(x)
    .tickSize(-height) 
    .tickPadding(10)   // Distance between axis and tick note 
    .tickSubdivide(true)
    .tickFormat(d3.format(".0"))    
    .orient("bottom");  
    
var yAxis = d3.svg.axis()
    .scale(y)
    .tickPadding(10)
    .tickSize(-width)
    .tickSubdivide(true)
    .tickFormat(d3.format(".3e")) // https://github.com/mbostock/d3/wiki/Formatting#d3_format  
    .orient("left");

var valueline = d3.svg.line()
    .x(function(d) { return x(d.samples); })
    .y(function(d) { return y(d.measurements); });

var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .scaleExtent([0.1, 50])
    .on("zoom", zoomed);

// Adding svg canvas
var svg = d3.select("body").append("svg")
    .call(zoom)
    .attr("width", width + margin.left + margin.right )
    .attr("height", height + margin.top + margin.bottom )
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Get the data
data=[{"SAMPLES":"1","MEASUREMENTS":"2","ID":"ch1"},{"SAMPLES":"2","MEASUREMENTS":"3","ID":"ch1"},{"SAMPLES":"1","MEASUREMENTS":"4","ID":"ch2"},{"SAMPLES":"3","MEASUREMENTS":"5","ID":"ch1"},{"SAMPLES":"2","MEASUREMENTS":"6","ID":"ch2"}];

data.forEach(function(d) {
    d.samples = +d.SAMPLES;
    d.measurements = +d.MEASUREMENTS;
});

console.log(data);

// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.samples; }));
y.domain([0, d3.max(data, function(d) { return d.measurements; })]);

// Creating X axis
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
    
// Drawing notations
svg.append("g")
        .attr("class", "x axis")
    .append("text")
        .attr("class", "axis-label")
        .attr("x", (width - margin.left)/2)
        .attr("y", height + margin.top + 45)
        .text('Samples'); 

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
 
svg.append("g")
        .attr("class", "y axis")
    .append("text")
        .attr("class", "axis-label")
        .attr("transform", "rotate(-90)")
        .attr("y", (-margin.left) + 10)
        .attr("x", -height/2)
        .text('Volts');

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

// Nest the entries by channel id (ID)
var dataNest = d3.nest()
    .key(function(d) {return d.ID;})
    .entries(data);

// set the colour scale    
var color = d3.scale.category10();

// Auto spacing for the legend
legendSpace = width/dataNest.length;

// Loop through each IDs / key to draw the lines and the legend labels
dataNest.forEach(function(d,i) {
    
    svg.append("path")
        .attr("class", "line")
        .attr("clip-path", "url(#clip)")
        .style("stroke", function() { // Add the colours dynamically
            return d.color = color(d.key); 
        })
        .attr("id", 'tag'+d.key.replace(/\s+/g, '')) // assign ID
        .attr("d", valueline(d.values))
        .style("stroke", function(){return d.color = color(d.key);});

    // Adding legends
    svg.append("text")

        // Setting coordinates and classes
        .attr("x", (legendSpace/2)+i*legendSpace) 
        .attr("y", height + (margin.bottom/2)+ 5)
        .attr("class", "legend")

        // Setting colors
        .style("fill",function(){
            return d.color = color(d.key);
        })

        // Setting 'click' events
        .on("click", function(){
            
            // Determine if current line is visible
            var active = d.active ? false : true,
            newOpacity = active ? 0 : 1;
            
            // Hide or show the elements based on the ID
            d3.select("#tag"+d.key.replace(/\s+/g, ''))
            .transition().duration(600)
            .style("opacity", newOpacity);

            // Update whether or not the elements are active
            d.active = active;
        })

        .text(function() {
            if (d.key == '28-00043b6ef8ff') {return "Inlet";}
            if (d.key == '28-00043e9049ff') {return "Ambient";}
            if (d.key == '28-00043e8defff') {return "Outlet";}
            else {return d.key;}
        })
})

// Zoom specific updates

function zoomed() {
  
    svg.select(".x.axis")
        .transition().duration(500)
        .call(xAxis);
    svg.select(".y.axis")
        .transition().duration(500)
        .call(yAxis);
    svg.selectAll('path.line')
        .transition().duration(500)
        .attr('d', valueline(data));
}
body {
	font: 12px Arial;
	margin: 50px;
}

.axis path {
    fill: none;
    stroke: #bbb;
    stroke-width: 2;
    shape-rendering: crispEdges;
}

.axis text {
    fill: #555;
}
 
.axis line {
    fill: none;
    stroke-width: 1;    
    stroke: #e7e7e7;
    shape-rendering: crispEdges;
}
 
.axis .axis-label {
    font-size: 14px;
}
 
path {
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}

.legend {
    font-size: 16px;
    font-weight: bold;
    text-anchor: middle;
}

Upvotes: 0

Views: 894

Answers (1)

eladcon
eladcon

Reputation: 5825

You need to bind your paths to your data, so you can call valueLine with the correct data for the path when zooming. Use d3 data and enter functions when adding a new path:

// choose all .line objects and append a path which is not already binded 
// by  comparing its data to the current key
svg.selectAll(".line").data([d], function (d) {
  return d.key;
})
.enter().append("path")
.attr("class", "line")

Then when you zoom, change the d attribute path by calling valueLine with the path's correct values:

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

Plunker

Upvotes: 2

Related Questions