如何正确缩放d3图表?

问题描述 投票:1回答:1

我制作了一个带有d3字云布局的图表。我想用d3.zoom()缩放它。问题是当我实现缩放功能时,SVG超出范围。像这个例子:https://codepen.io/bitbyte/pen/oVKGjx

var words = ["two", "two", "seven", "seven", "seven", "seven", "seven", "seven", "seven", "three", "three", "three", "eight", "eight", "eight", "eight", "eight", "eight", "eight", "eight", "five", "five", "five", "five", "five", "four", "four", "four", "four", "nine", "nine", "nine", "nine", "nine", "nine", "nine", "nine", "nine", "one", "ten", "ten", "ten", "ten", "ten", "ten", "ten", "ten", "ten", "ten", "six", "six", "six", "six", "six", "six"]
        .map(function(d,i) {
            //console.log(d);
            return {text: d, size: -i};
        });

var fontName = "Impact",
    cWidth = 720,
    cHeight = 400,
    svg,
    wCloud,
    bbox,
    ctm,
    bScale,
    bWidth,
    bHeight,
    bMidX,
    bMidY,
    bDeltaX,
    bDeltaY;

var cTemp = document.createElement('canvas'),
    ctx = cTemp.getContext('2d');
    ctx.font = "100px " + fontName;

var fRatio = Math.min(cWidth, cHeight) / ctx.measureText(words[0].text).width,
    fontScale = d3.scale.linear()
        .domain([
            d3.min(words, function(d) { return d.size; }), 
            d3.max(words, function(d) { return d.size; })
        ])
        //.range([20,120]),
        .range([20,100*fRatio/2]), // tbc
    fill = d3.scale.category20();

d3.layout.cloud()
    .size([cWidth, cHeight])
    .words(words)
    //.padding(2) // controls
    .rotate(function() { return ~~(Math.random() * 2) * 90; })
    .font(fontName)
    .fontSize(function(d) { return fontScale(d.size) })
    .on("end", draw)
    .start();

function draw(words, bounds) {
    // move and scale cloud bounds to canvas
    // bounds = [{x0, y0}, {x1, y1}]
    bWidth = bounds[1].x - bounds[0].x;
    bHeight = bounds[1].y - bounds[0].y;
    bMidX = bounds[0].x + bWidth/2;
    bMidY = bounds[0].y + bHeight/2;
    bDeltaX = cWidth/2 - bounds[0].x + bWidth/2;
    bDeltaY = cHeight/2 - bounds[0].y + bHeight/2;
    bScale = bounds ? Math.min( cWidth / bWidth, cHeight / bHeight) : 1;



    svg = d3.select(".cloud").append("svg")
        .attr("width", cWidth)
        .attr("height", cHeight)
     .call(d3.behavior.zoom().on("zoom", function () {
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
  }))


    wCloud = svg.append("g")

        .attr("transform", "translate(360,200)")
        .selectAll("text")
        .data(words)
        .enter().append("text")
        .style("font-size", function(d) { return d.size + "px"; })
        .style("font-family", fontName)
        .style("fill", function(d, i) { return fill(i); })
        .attr("text-anchor", "middle")
        .transition()
        .duration(500)
        .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .text(function(d) { return d.text; });

    bbox = wCloud.node(0).getBBox();


};

制作像这样https://bl.ocks.org/sgruhier/50990c01fe5b6993e82b8994951e23d0的缩放图表的正确方法是什么

使用方形固定容器,其中包含SVG,并且在放大时不会移动所有页面。

javascript d3.js svg zoom bounds
1个回答
1
投票

这是一个更新的codepen与您的解决方案:https://codepen.io/cstefanache/pen/ZPgmwy

您必须在不直接在SVG DOM上的组元素上应用转换,以便允许用户与SVG视口进行进一步的鼠标交互。

.call(d3.behavior.zoom().on("zoom", function () {
    groupElement.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))

对原始codepen的更改是存储对单词云组的引用以便使用并将所有更改应用于该引用

wCloud = svg.append("g");   
wCloud.selectAll("text")
    .data(words)
    ...

此外,删除了初始变换,因为如果group元素最初具有变换值,则它将被替换为d3事件的新变换,该变换将在x,y位置之间具有较大差异,并且将在第一次变换时生成闪烁。

为了避免这种情况,组的初始位置没有转换,但是相对于视口的中心放置了单词:

.attr("transform", function(d) {
    return "translate(" + [bMidX + d.x, bMidY + d.y] + ")rotate(" + d.rotate + ")";
})
© www.soinside.com 2019 - 2024. All rights reserved.