d3有限缩放图 [英] d3 graph with limited zoom

查看:133
本文介绍了d3有限缩放图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了一个d3线图,从CSV文件读取数据,然后绘制多个行,鼠标悬停事件反应。它使用以下代码平移和缩放工作正常(对不起,它是这么长,略显不整洁,但我觉得最好显示完整的代码):

  d3.csv(ijisb.csv,function(error,data){

var margin = {top:50,right:120,bottom:50,left: 70},
width = 1200 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;

var parseDate = d3.time。格式(%m%d)。parse;

var color = d3.scale.category20();

color.domain(d3.keys ]; filter(function(key){return key!==date;}));

data.forEach(function(d){
d.date = parseDate d。);
});

var sources = color.domain()。map(function(name){
return {
name:name,
values:data.map(function(d){
return {date:d.date,temperature:+ d [name]};
})
};
});

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

var y = d3.scale.linear()
.range([height,0])
.domain([
0,
d3 .max(sources,function(c){return d3.max(c.values,function(v){return v.temperature;});})
]);

var xAxis = d3.svg.axis()
.scale(x)
.orient(bottom)
.ticks b.tickFormat(d3.time.format(%b%d));

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

var line = d3.svg.line()
.defined(function(d){return d.temperature> = 0;})
.x d){return x(d.date);})
.y(function(d){return y(d.temperature);});

var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1,8])
.on(zoom,zoomed);

var svg = d3.select(body)append(svg)
.attr(width,100%)
.attr height,100%)
.attr(viewBox,0 0 1200 800)
.append(g)
.attr (+ margin.left +,+ margin.top +))
.call(zoom);

var rect = 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(12)
.tickFormat(d3.time.format(%b%d));
};

var make_y_axis = function(){
return d3.svg.axis()
.scale(y)
.orient(left)$ b $ (5);
};

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

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

svg.append(g)
.attr(class,x grid)
.attr(transform 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 source = svg.selectAll(。source)
.data(sources)
.enter()。append(g)
.attr (class,source);

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

source.append(path)
.data(sources)
.attr(class,line)
.attr路径,url(#clip))
.attr(d,function(d){return line(d.values);})
.style d){return color(d.name);})
.style(opacity,0.8)
.on(mouseover,function(d){
d3.select this)
.style(stroke,function(d){return color(d.name);})
.style(opacity,1.0)
.style -width,2.5);
this.parentNode.parentNode.appendChild(this.parentNode);
d3.select('#text-'+ d.name)
.style
.style(font-weight,700);
})
.on(mouseout ,function(d){
d3.select(this)
.transition()
.duration(250)
.style color(d.name);})
.style(stroke-width,1.5)
.style(opacity,0.8);
d3.select('#text-'+ d.name)
.transition()
.duration(250)
.style(fill,function {return color(d.name);})
.style(font-weight,400);
})
.attr(id,function(d,i){returnpath-+ d.name;});

source.append(text)
.datum(function(d){return {name:d.name};})
.attr(x函数(d,i){return width + 10;})
.attr(y,function(d,i){return(i *(height / 16));})

.on(mouseover,function(d){
d3.select('#path-' + d.name)
.style(stroke,function(d){return color(d.name);})
.style(opacity,1.0)
.style (stroke-width,2.5);
this.parentNode.parentNode.appendChild(this.parentNode);
d3.select(this)
.style d){return color(d.name);})
.style(font-weight,700);
})
.on {
d3.select('#path-'+ d.name)
.transition()
.duration(250)
.style ){return color(d.name);})
.style(stroke-width,1.5)
.style(opacity,0.8);
d3.select(this)
.transition()
.duration(250)
.style(fill,function(d){return color(d.name) ;})
.style(font-weight,400);
})
.text(function(d){return d.name;})
.attr(font-family,sans-serif)
.attr (font-size,14px)
.attr(id,function(d,i){returntext-+ d.name;}
);

var minT = new Date('01 / 01/1900'),maxT = new Date('01 / 01/2002'),w = $(window).width

function zoomed(){
d3.event.translate;
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() ;
source.select(。line)
.attr(d,function(d){return line(d.values);})
.style function(d){return color(d.name);});
}

});

我遇到的问题是,我想限制平移和缩放,要在屏幕外缩放或平移的图形。我可以通过设置scaleExtent对缩放(在上面的例子中实现)和更改缩放函数为:

  function zoomed(){

var t = zoom.translate(),

tx = t [0];
ty = t [1];

tx = Math.min(tx,0);
zoom.translate([tx,ty]);

d3.event.translate;
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() ;
source.select(。line)
.attr(d,function(d){return line(d.values);})
.style function(d){return color(d.name);});
}

这将x轴最小值限制为零。然而,我很难尝试,但我不能限制x轴的最大值,这意味着图形仍然可以向右偏移太远。



任何帮助?

解决方案

感谢您的支持帮助,我是通过下面的代码到底做的:

  var t = zoom.translate(),
s = zoom.scale();

tx = Math.min(0,Math.max(width *(1 - s),t [0]))
ty = Math.min(0,Math.max(height *(1 - s),t [1]));

zoom.translate([tx,ty]);

困难在于在各种缩放级别上限制图形,这现在解决了。 d3.event.translate和d3.event.scale语句也是不必要的,应该已删除。


I have implemented a d3 line graph which reads data from a CSV file, and then plots multiple lines which react to mouseover events. It works fine with pan and zoom using the following code (sorry that it is so long and slightly untidy but I felt it best to display the full code):

    d3.csv("ijisb.csv", function(error, data) {

    var margin = {top: 50, right: 120, bottom: 50, left: 70},
    width = 1200 - margin.left - margin.right,
    height = 800 - margin.top - margin.bottom;

    var parseDate = d3.time.format("%m%d").parse;

    var color = d3.scale.category20();

    color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));

    data.forEach(function(d) {
        d.date = parseDate(d.date);
    });

    var sources = color.domain().map(function(name) {
        return {
            name: name,
            values: data.map(function(d) {
                return {date: d.date, temperature: +d[name]};
            })
        };
    });

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

    var y = d3.scale.linear()
        .range([height, 0])
        .domain([
        0,
        d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
    ]);

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .ticks(12)
        .tickFormat(d3.time.format("%b %d"));

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

    var line = d3.svg.line()
        .defined(function(d) { return d.temperature >= 0; })
        .x(function(d) { return x(d.date); })
        .y(function(d) { return y(d.temperature); });

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

    var svg = d3.select("body").append("svg")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("viewBox", "0 0 1200 800")
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);

    var rect = 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(12)
            .tickFormat(d3.time.format("%b %d"));
    };

    var make_y_axis = function () {
        return d3.svg.axis()
            .scale(y)
            .orient("left")
            .ticks(5);
    };

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

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

    var source = svg.selectAll(".source")
    .data(sources)
    .enter().append("g")
    .attr("class", "source");

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

    source.append("path")
        .data(sources)
        .attr("class", "line")
        .attr("clip-path", "url(#clip)")
        .attr("d", function(d) { return line(d.values); })
        .style("stroke", function(d) {return color(d.name);})
        .style("opacity", 0.8)
        .on("mouseover", function(d){
            d3.select(this)
                .style("stroke",function(d) {return color(d.name);})
                .style("opacity", 1.0)
                .style("stroke-width", 2.5);
                this.parentNode.parentNode.appendChild(this.parentNode);
            d3.select('#text-' + d.name)
                .style("fill",function(d) {return color(d.name);})
                .style("font-weight", 700);
        })
        .on("mouseout", function(d) {
            d3.select(this)
                .transition()
                .duration(250)
                .style("stroke", function(d) {return color(d.name);})
                .style("stroke-width", 1.5)
                .style("opacity", 0.8);
            d3.select('#text-' + d.name)
                .transition()
                .duration(250)
                .style("fill", function(d) {return color(d.name);})
                .style("font-weight", 400);
        })
        .attr("id", function(d, i) { return "path-" + d.name; }); 

    source.append("text")
        .datum(function(d) { return {name: d.name}; })
        .attr("x", function(d, i) { return width+10; })
        .attr("y", function(d, i) { return (i*(height/16)); })
        .style("fill", function(d) {return color(d.name);})
        .on("mouseover", function(d){
            d3.select('#path-' + d.name)
                .style("stroke",function(d) {return color(d.name);})
                .style("opacity", 1.0)
                .style("stroke-width", 2.5);
                this.parentNode.parentNode.appendChild(this.parentNode);
            d3.select(this)
                .style("fill",function(d) {return color(d.name);})
                .style("font-weight", 700);
        })
        .on("mouseout", function(d) {
            d3.select('#path-' + d.name)
                .transition()
                .duration(250)
                .style("stroke", function(d) {return color(d.name);})
                .style("stroke-width", 1.5)
                .style("opacity", 0.8);
            d3.select(this)
                .transition()
                .duration(250)
                .style("fill", function(d) {return color(d.name);})
                .style("font-weight", 400);
        })
        .text(function(d) { return d.name; })
        .attr("font-family","sans-serif")
        .attr("font-size","14px")
        .attr("id", function(d, i) { return "text-" + d.name; }
        ); 

    var minT = new Date('01/01/1900'), maxT = new Date('01/01/2002'), w = $(window).width();

function zoomed() {
        d3.event.translate;
        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(""));
    source.select(".line")
        .attr("d", function(d) { return line(d.values); })
        .style("stroke", function(d) {return color(d.name);});  
    }

    });

The problem I have is that I want to limit the panning and zooming so that it is not possible for the graph to be zoomed or panned out offscreen. I can do this by setting the scaleExtent on the zoom (which is implemented in the above example) and changing the zoomed function to:

    function zoomed() {

    var t = zoom.translate(),

    tx = t[0];
    ty = t[1];

    tx = Math.min(tx, 0);
    zoom.translate([tx, ty]);

    d3.event.translate;
    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(""));
    source.select(".line")
        .attr("d", function(d) { return line(d.values); })
        .style("stroke", function(d) {return color(d.name);});
}

This limits the x-axis minimum to zero. However hard I try however, I cannot limit the maximum value of the x-axis, which means the graph can still pan too far to the right.

Any help? I hope this makes sense!

Nick

解决方案

Thanks for the help, I did it by the following code in the end:

var t = zoom.translate(),
s = zoom.scale();

tx = Math.min(0, Math.max(width * (1 - s), t[0]));
ty = Math.min(0, Math.max(height * (1 - s), t[1]));

zoom.translate([tx, ty]);

The difficulty was in bounding the graph at various zoom levels, which this now solves. The d3.event.translate and d3.event.scale statements were also unnecessary, and should have been removed.

这篇关于d3有限缩放图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆