D3.js 设置初始缩放级别

39

我设置了几个图形以在容器上缩放,效果很好。然而,在初始加载时,缩放级别太接近了。有没有一种方法可以设置初始缩放级别,避免首先要缩小?我熟悉.scale()方法,但尝试实施后并没有成功。这是正确的方法还是我漏掉了什么?

至于缩放方面,我目前拥有以下内容:

var margin = {top: 20, right: 120, bottom: 20, left: 120},
    width = 50000 - margin.right - margin.left,
    height = 120000 - margin.top - margin.bottom;

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

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

var tree = d3.layout.tree()
    .size([height, width])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.x, d.y]; });

function zoom(d) {        
  svg.attr("transform",
      "translate(" + d3.event.translate + ")"+ " scale(" + d3.event.scale + ")");
}

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .attr("pointer-events", "all")
    .call(d3.behavior.zoom()
        .x(x)
        .y(y)
        .scaleExtent([0,8])
        .on("zoom", zoom))
        .append('g');

svg.append('rect')
    .attr('width', width*5)
    .attr('height', height)
    .attr('border-radius', '20')
    .attr('fill', 'sienna');

既然您正在使用SVG变换scale进行缩放,为什么不静态地设置一个比例值,以获得所需的缩放级别呢? - Lars Kotthoff
听起来很棒!我该怎么做? - Jakub Svec
Lars,比例尺的值是如何静态设置的? - Jakub Svec
7个回答

37

D3v4的答案

如果您在这里寻找的是D3 v4版本的相同内容,

var zoom = d3.zoom().on("zoom", function(){
    svg.attr("transform", d3.event.transform);
});

vis = svg.append("svg:svg")
     .attr("width", width)
     .attr("height", height)
     .call(zoom) // here
     .call(zoom.transform, d3.zoomIdentity.translate(100, 50).scale(0.5))
     .append("svg:g")
     .attr("transform","translate(100,50) scale(.5,.5)");

4
无法在d3 v5上运行此解决方案。你知道是否有什么变化了吗? - Le Sparte
这个解决方案对我很有效!在最新版本的d3中,事件对象不可用。您可以通过传递给函数的元素访问它:var zoom = d3.zoom().on('zoom', function(e){ svg.attr('transform', e.transform)}); - Soufyane Hedidi

36

我最终通过将初始转换和缩放行为设置为相同值来使其正常工作。

var zoom = d3.behavior.zoom().translate([100,50]).scale(.5);

vis = svg.append("svg:svg")
     .attr("width", width)
     .attr("height", height)
     .call(zoom.on("zoom",zooming))
           .append("svg:g")
           .attr("transform","translate(100,50)scale(.5,.5)");  

17

适用于 d3.js v4

这类似于 davcs86的答案,但它重用了初始变换并实现了缩放函数。

// Initial transform to apply
var transform = d3.zoomIdentity.translate(200, 0).scale(1);
var zoom = d3.zoom().on("zoom", handleZoom);

var svg = d3.select("body")
  .append('svg')
  .attr('width', 800)
  .attr('height', 300)
  .style("background", "red")
  .call(zoom)                       // Adds zoom functionality
  .call(zoom.transform, transform); // Calls/inits handleZoom

var zoomable = svg
  .append("g")
  .attr("class", "zoomable")
  .attr("transform", transform);    // Applies initial transform

var circles = zoomable.append('circle')
  .attr("id", "circles")
  .attr("cx", 100)
  .attr("cy", 100)
  .attr('r', 20);

function handleZoom(){
  if (zoomable) {
    zoomable.attr("transform", d3.event.transform);
  }
};

查看示例:jsbin链接


感谢在handleZoom中使用if条件。 - Amaan Iqbal

15

如果还有人遇到问题,我将此答案作为已接受答案的补充:

让我真正理解这个东西的是看到了这里

话虽如此,我设置了三个变量:

scale、zoomWidth和zoomHeight

scale是您想要缩放的初始比例,然后

zoomWidth和zoomHeight定义如下:

zoomWidth = (width-scale*width)/2
zoomHeight = (height-scale*height)/2

其中 width 和 height 是 "vis" svg 元素的宽度和高度。

然后修改上面的翻译为:

.attr("transform", "translate("+zoomWidth+","+zoomHeight+") scale("+scale+")")

以及缩放功能:

d3.behavior.zoom().translate([zoomWidth,zoomHeight]).scale(scale)

这样做的效果是确保在可视化加载时,您的元素被缩放并居中显示。如果有帮助,请告诉我!干杯。

2
我从JSON中加载了缩放级别,现在我正在尝试在SVG加载时重新创建缩放级别。你能发布完整的解决方案吗? :) - Amiga500
2
如果那个链接还能用就太好了...感谢Wayback Archive - Dan
更新我的原始答案以引用存档链接。谢谢! - deweyredman
在我的情况下,zoomWidthzoomHeight 分别对应 "offsetLeft" 和 "offsetTop"。 - Jodo

6

D3JS 6 答案

假设你希望初始位置和比例为 x, y, scale

const zoom = d3.zoom();

const svg = d3.select("#containerId")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .call(zoom.transform, d3.zoomIdentity.translate(x, y).scale(scale)
    .call(zoom.on('zoom', (event) => {
        svg.attr('transform', event.transform);
     }))
    .append("g")
    .attr('transform', `translate(${x}, ${y})scale(${k})`);
.call(zoom.transform, d3.zoomIdentity.translate(x, y).scale(scale)这行代码确保当缩放事件被触发时,event.transform变量将考虑到平移和比例尺。接下来的一行处理缩放,而最后一行仅在“启动”时应用平移和比例尺。

4

我在使用react和d3时遇到一个困扰,就是初始缩放不起作用。我尝试了这里的解决方案,但都不起作用。最终解决办法是使用一个初始比例因子和位置,然后根据这些比例因子和位置更新缩放函数。

const initialScale = 3;
const initialTranslate = [
  width * (1 - initialScale) / 2,
  height * (1 - initialScale) / 2,
];

const container = svg
  .append('g')
  .attr(
    'transform',
    `translate(${initialTranslate[0]}, ${initialTranslate[1]})scale(${initialScale})`
  );

缩放功能应该是这样的:
svg.call(
  zoom().on('zoom', () => {
    const transformation = getEvent().transform;
    let {x, y, k} = transformation;
    x += initialTranslate[0];
    y += initialTranslate[1];
    k *= initialScale;

    container.attr('transform', `translate(${x}, ${y})scale(${k})`);
  })
);

如果你注意到getEvent()是一个函数,那是因为在我的情况下从d3-selection导入事件没有起作用。所以我不得不这样做:

const getEvent = () => require('d3-selection').event;

1
在d3版本5中,它是:d3.event.transform - Carnaru Valentin

1
根据比例尺计算图表的初始点,可以这样做:
init_scale = [2, 8]
configInitialScaleZoom(container: any, init_scale: number[], zoom: any, options: any) {
    if (!container) return;

    const margin_left = options.margin.left;
    const margin_top = options.margin.left;

    const zoom_width = (margin_left * init_scale[0] - margin_left) * -1;
    const zoom_height = (margin_top * init_scale[0] - margin_top) * -1;

    container.call(zoom.transform, d3.zoomIdentity.translate(zoom_width, zoom_height).scale(init_scale[0]));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接