如何正确缩放 d3 图表?
How to zoom a d3 chart correctly?
我做了一个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 的方形固定容器,并且在放大页面时不会四处移动。
这是包含您的解决方案的更新代码笔: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 + ")";
})
我做了一个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 的方形固定容器,并且在放大页面时不会四处移动。
这是包含您的解决方案的更新代码笔: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 + ")";
})