如何使用d3js动态创建append-svg行



我正在尝试为可缩放/可平移的图形绘制标记。我的当前版本可在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);
}

在这个例子中,我已经能够将静态线添加到我的d3图中,我试图实现的是使标记线和文本"test"一起沿着图移动。

我尝试过使用一个带有行生成器的d3.svg.line(),但它最终没有得到对d的引用。我尝试过的另一个版本是创建一个函数,如下所示,但没有得到d的引用,并在零处绘制线。在这里,我试图画出一条线,当且仅当数据中存在标记标记时。默认情况下,当填充数据时,我已经确保它有Number.NaN,而我不需要绘制标记。

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

根据我对您问题的回答,我做了一些小的更改。在缩放处理程序zoomed()中,您需要更改x1&markerx2属性和markerTextx属性。

该函数在每个缩放事件上启动,根据缩放和轴移动或重新绘制内容。

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/

这可以通过使用d3轴来解决。工作示例可在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]})

};

最新更新