Как правильно масштабировать график d3? - PullRequest
1 голос
/ 29 марта 2019

Я сделал диаграмму с макетом облака слов 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, а неперемещаясь по всей странице, когда вы увеличиваете ее.

1 Ответ

1 голос
/ 29 марта 2019

Вот обновленная кодовая ручка с вашим решением: 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 + ")")
}))

изменения в вашей исходной кодовой ручке состояли в том, чтобы сохранить ссылку на группу слов в облаке, чтобы ее можно было использовать, и применить все изменения к этой ссылке

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

Также первоначальное преобразование было удалено, потому что, если элемент группы изначально имеет значение преобразования, он будет заменен новым преобразованием из события d3, которое будет иметь большие различия между позициями x, y, и будет генерировать мерцание на первом преобразование.

Во избежание этого исходная позиция группы не имеет преобразования, но слова были размещены относительно центра области просмотра:

.attr("transform", function(d) {
    return "translate(" + [bMidX + d.x, bMidY + d.y] + ")rotate(" + d.rotate + ")";
})
...