Javascript 在d3缩放中更改矩形尺寸

Javascript 在d3缩放中更改矩形尺寸,javascript,d3.js,zooming,Javascript,D3.js,Zooming,我正在使用d3构建一个钢琴卷编辑器(看起来有点像)。我需要始终将矩形捕捉到网格上,以便在平移或缩放时,形状将保持相对于网格线。我进进出出时是否重新绘制垂直网格线并不重要,但水平网格线的数量应始终保持不变,并且矩形形状始终锁定。这里可以看到一个不太有效的例子: 我可以看到很多d3缩放类型的例子,但我找不到任何东西来解决这种问题。我想我只是不理解在使用缩放功能时如何正确缩放形状。此外,在试图让这项工作,我注意到平移和缩放似乎已经变得有点不可靠,不知道为什么 无论如何,如果有人对如何解决这个问题有任何

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

我可以看到很多d3缩放类型的例子,但我找不到任何东西来解决这种问题。我想我只是不理解在使用缩放功能时如何正确缩放形状。此外,在试图让这项工作,我注意到平移和缩放似乎已经变得有点不可靠,不知道为什么

无论如何,如果有人对如何解决这个问题有任何想法,我们将不胜感激。JSFIDLE上的代码如下所示:

更新:只是为了(希望!)澄清-水平轴和垂直轴都需要缩放。约束条件是,水平轴网线的数量需要保持不变,并且形状必须锁定在轴网线上,以便尺寸永远不变。如果矩形的宽度和高度均为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;
            })



}

如果不希望缩放行为更新
yScale
,只需删除
.y(yScale)
行即可

缩放行为将简单地构造为:

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

它只会更新
xScale

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