1

I am attempting to draw markers to a zoomable / pannable graph. My current version is available at https://jsfiddle.net/n2enn80o/

raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]};

var data =[];
for(var i=0;i<raw.l2.length;i++)
{
    var marker = Number.NaN;

    for(var j=0;j<raw.marker1.length;j++)
    {
        if(i==raw.marker1[j])
        {
            marker=i;
            break;
        }
    }
    var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker}
    data.push(obj)
}

margin = {
    top: 20,
    right: 20,
    bottom: 20,
    left: 45
};

width = 1800 - margin.left - margin.right;
height = 600 - margin.top - margin.bottom;

var x = d3.time.scale()
    .domain(d3.extent(data, function (d) {
    return d.date;
}))
    .range([0, width]);

var y = d3.scale.linear()
    .domain(d3.extent(data, function (d) {
    return d.value;
}))
    .range([height, 0]);

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



var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .on("zoom", zoomed);

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");

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(y)
        .orient("left")
        .ticks(5);
};

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .ticks(5);

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

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(5);

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


var marker = svg.append("line")
    .attr("x1",100)
    .attr("y1", 0)     
    .attr("x2",100)
    .attr("y2", height)
    .attr("class", "marker")

svg.append("text")
    .attr("x", 100)
    .attr("y", 0)
    .attr("dy", ".35em")
    .attr("dx", 5)
    .attr("class", "marker-text")
    .text(function(d) { return "test"; });

svg.append("g")
    .attr("class", "x grid")
    .attr("transform", "translate(0," + height + ")")
    .call(make_x_axis()
        .tickSize(-height, 0, 0)
        .tickFormat(""));

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

var clip = svg.append("svg:clipPath")
    .attr("id", "clip")
    .append("svg:rect")
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", width)
    .attr("height", height);

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

chartBody.append("svg:path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

function zoomed() {
    console.log(d3.event.translate);
    console.log(d3.event.scale);
    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);
    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.select(".line")
        .attr("class", "line")
        .attr("d", line);
}

I have been able to add static lines to my d3 plot in the example, what i am trying to achieve is to make the marker line along with the text "test" to be moving along with the graph.

What I have tried is to use a d3.svg.line() with a line generator, but it ends up not getting the reference to d. Another version I have attempted is to create a function as below but that does not get the reference of d, and draws the line at zero. Here i attempted to draw the line if and only if the marker tag was present in the data. By default when populating the data i have ensured that it has Number.NaN when i dont need to draw the marker.

var marker = svg.append("line")
    .attr("x1",function(d) { if(d.marker!=Number.NaN)  return x(d.date); })
    .attr("y1", 0)     
    .attr("x2",function(d) { if(d.marker!=Number.NaN)  return x(d.date); })
    .attr("y2", height)
    .attr("class", "marker")
1
  • Inside function zoomed() you need to change the x1 & x2 attributes of marker Commented Aug 4, 2016 at 11:03

2 Answers 2

1

I have made a couple of small changes, as per my reply to your question. Inside your zoom handler zoomed() you need to change the x1 & x2 attributes of marker, and the x attr of markerText.

This function fires on each zoom event to move stuff around or redraw stuff according to your zoom, and your axes.

raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]};

var data =[];
for(var i=0;i<raw.l2.length;i++)
{
    var marker = Number.NaN;

    for(var j=0;j<raw.marker1.length;j++)
    {
        if(i==raw.marker1[j])
        {
            marker=i;
            break;
        }
    }
    var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker}
    data.push(obj)
}

margin = {
    top: 20,
    right: 20,
    bottom: 20,
    left: 45
};

width = 1800 - margin.left - margin.right;
height = 600 - margin.top - margin.bottom;

var x = d3.time.scale()
    .domain(d3.extent(data, function (d) {
    return d.date;
}))
    .range([0, width]);

var y = d3.scale.linear()
    .domain(d3.extent(data, function (d) {
    return d.value;
}))
    .range([height, 0]);

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



var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .on("zoom", zoomed);

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");

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(y)
        .orient("left")
        .ticks(5);
};

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .ticks(5);

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

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(5);

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




svg.append("g")
    .attr("class", "x grid")
    .attr("transform", "translate(0," + height + ")")
    .call(make_x_axis()
        .tickSize(-height, 0, 0)
        .tickFormat(""));

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

// Moved this after you append your grids 
var marker = svg.append("line")
    .attr("x1",100)
    .attr("y1", 0)     
    .attr("x2",100)
    .attr("y2", height)
    .attr("class", "marker")

// Moved this after you append your grids & saved it to a var for later use
var markerText = svg.append("text")
    .attr("x", 100)
    .attr("y", 0)
    .attr("dy", ".35em")
    .attr("dx", 5)
    .attr("class", "marker-text")
    .text(function(d) { return "test"; });

var clip = svg.append("svg:clipPath")
    .attr("id", "clip")
    .append("svg:rect")
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", width)
    .attr("height", height);

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

chartBody.append("svg:path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

function zoomed() {
    console.log(d3.event.translate);
    console.log(d3.event.scale);
    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);
    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.select(".line")
        .attr("class", "line")
        .attr("d", line);

        // Position at the start time according to your x scale. x(val)
        // It's not clear from your question where you want to position it 
        var markerPos = x(raw.startts);

        // Move marker to position
        marker.attr("x1", markerPos ).attr("x2", markerPos );

        // Move marker text to position
        markerText.attr("x", markerPos );

}

Fiddle: https://jsfiddle.net/kqnLfkvw/1/

Sign up to request clarification or add additional context in comments.

1 Comment

thankyou ksav this was helpful, i have managed to solve it in a similar way.
0

This can be solved by using d3 axis. A working example is available at https://jsfiddle.net/3gww76s0/

var make_x_marker = function (scale=1, transform=[0,0]) {

    console.log(transform)
    var markers =[];
    var markerLabels={};
    for (i=0; i<raw.marker1.length; i++)
    {
    var value=transform[0]+scale*(1/244.140625*1000)*raw.marker1[i];
     markers.push(value)
     markerLabels[value]="A"+Math.floor(Math.random()*26);
    }

    return d3.svg.axis()
        .orient("top")
        .tickValues(markers)
        .tickSize(height-15)
        .tickFormat(function(d){return markerLabels[d]})


};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.