【问题标题】:Changing rectangle dimensions in d3 zoom在 d3 缩放中更改矩形尺寸
【发布时间】:2015-01-05 10:50:36
【问题描述】:

我正在使用 d3 构建一个钢琴卷帘编辑器(看起来有点像 this)。我需要将矩形始终捕捉到网格上,因此当我平移或缩放时,形状将保持相对于网格线。在我移入和移出时是否重绘垂直网格线并不重要,但水平网格线的数量应始终保持不变,并且矩形形状始终锁定。在这里可以看到一个不太有效的例子:http://jsfiddle.net/jgab3103/e05qj4hy/

我可以在这个地方看到很多 d3 缩放类型的示例,但我找不到任何解决此类问题的方法。我想我只是不了解在使用缩放功能时如何正确缩放形状。此外,在尝试让它工作时,我注意到平移和缩放似乎变得有点不可靠,不知道为什么。

无论如何,如果有人对如何解决此问题有任何想法,将不胜感激。 jsfiddle上的代码如下:

更新:只是为了(希望!)澄清 - 水平轴和垂直轴都需要缩放。约束是水平网格线的数量需要保持不变,并且形状必须锁定在网格线上,因此尺寸永远不会改变。如果一个矩形以宽度和高度为 1 开始,缩放时总是需要保留它。

//Data for note shapes
var noteData = [
          {frequency: 3, duration:1, startPoint: 1},
          {frequency: 6, duration:1, startPoint: 2},
          {frequency: 5, duration:1, startPoint: 3},
          {frequency: 4, duration:1, startPoint: 4}
          ];

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

width = 400 - margin.left - margin.right;
height = 200 - margin.top - margin.bottom;


//SCALES
var xScale = d3.scale.linear()
    .domain([0,width])
    .range([0, width])


var yScale = d3.scale.linear()
    .domain([0,width])
    .range([0, height]);

var heightScale = d3.scale.linear()
    .domain([0,100])
    .range([0,height]);

//Set up zoom 

var zoom = d3.behavior.zoom()
    .x(xScale)
    .y(yScale)
    .scaleExtent([1,100])
    .scale([50])
    .on("zoom", zoomed);

// Create SVG space and centre it
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);
// Append a rect on top
var rect = svg.append("svg:rect")
    .attr("width", width)
    .attr("height", height)
    .attr("class", "plot");



var noteRange = d3.range(0,88);
var measureRange = d3.range(0,16);


var make_x_axis = function () {
    return d3.svg.axis()
        .scale(xScale)
        .orient("bottom")
        .ticks(10);
};




var make_y_axis = function () {
    return d3.svg.axis()
        .scale(yScale)
        .orient("left")
        .tickValues(noteRange);
};

var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .ticks(10);
    //.tickValues([2,5,7,9]);

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

var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left")
    .tickValues(noteRange);

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


var rectGroup = svg.append("g")


var notes = rectGroup
        .selectAll("rect")
        .data(noteData)
        .enter()
            .append("rect")
            .attr("x",function(d){
              return xScale(d.startPoint)
            })
            .attr("y",function(d){
              return yScale(d.frequency)
            })
            .attr("width",function(d) {
              return 50;
            })
            .attr('class', 'rect')
            .attr("height", function(d) {
              return 23;
            })


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

    rectGroup.selectAll("rect")
         .attr('class', 'rect')
         .attr("x",function(d){
          return xScale(d.startPoint);
        })
         .attr("y",function(d){
          return yScale(d.frequency);
        })
         .attr('width', function(d) {
          return 50;
        })
        .attr("height", function(d) {
              return 23;
            })



}

【问题讨论】:

  • 是否缩放横轴,保持纵轴比例不变?
  • 这可能与您的问题无关,但是您为什么要使用一组 D3 轴作为视觉轴,并在每次缩放时为网格创建一组全新的轴?
  • 顺便说一句,您可以重构此代码以删除大量重复项,并使您和 StackOverflow 上的其他人更容易看到发生了什么。
  • 对不起,我可能解释得很糟糕。我很高兴水平轴和垂直轴都可以缩放。约束是水平网格线的数量需要保持不变,并且形状必须锁定在网格线上,因此形状尺寸永远不会改变。问题是当我缩放时,形状不会保持正确的尺寸(即保留它们开始时的宽度和高度)。我已经更新了上面的小提琴,让它更直观一点。您可以看到底部矩形以高度和宽度 1 开始,它不再与网格线对齐。
  • @Couchand - 我正在创建新轴,因为我对此知之甚少!将尝试重构代码

标签: javascript d3.js zooming


【解决方案1】:

如果您不希望 yScale 被缩放行为更新,只需删除行 .y(yScale) 就可以了。

将简单地构造缩放行为:

var zoom = d3.behavior.zoom()
    .x(xScale)
    .scaleExtent([1,100])
    .scale([50])
    .on("zoom", zoomed);

它只会更新xScale。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多