【问题标题】:D3 selective ZoomD3 选择性缩放
【发布时间】:2012-10-16 14:03:44
【问题描述】:

我正在开发具有一些附加功能的强制导向图布局:可选链接/节点、工具提示、鱼眼效果,以及 -- 对我的问题很重要 -- 缩放和平移。

现在,缩放效果很好,如下所示:

d3 ... .append('svg:g').call(d3.behavior.zoom().on("zoom", redraw))... 

重绘函数看起来像这样...

function redraw() {
  trans = d3.event.translate;
  scale = d3.event.scale;
  vis.attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
}

但是,此方法会缩放整个 SVG 图形,包括字体大小、图形边缘、节点周围的线条笔划宽度等。

是否有可能缩放某些元素?到目前为止我看到的唯一解决方案是写这样一行(从这里获取http://jsfiddle.net/56RDx/2/

node.attr("font-size", (nodeFontSize / d3.event.scale) + "px");

在重绘方法中,基本上是在运行时反转某些元素的缩放。然而,我的问题是(除了这是一个丑陋的黑客之外),我的边缘宽度是在图形绘制上动态生成的(根据一些图形属性......),所以这种“反转”方法不起作用......

【问题讨论】:

  • 为什么不在单个 SVG 形状上将 scale() 设置为较小的数量?
  • 你有演示吗?你想缩放什么?
  • @A.M.K 代码有点庞大,很难将其放入演示中......但这是许多使用功能的来源:bl.ocks.org/2514276#index.html
  • @A.M.K 我将如何仅针对某些 SVG 形状将 ''scale()'' 设置为较小的数量?
  • 没关系,这行不通,请看我下面的答案。

标签: javascript d3.js zooming force-layout


【解决方案1】:
  1. 您可以为要触发缩放的元素添加一个类:

    d3 ... .append('svg:g').classed("some_classname", true).call(d3.behavior.zoom().on("zoom", redraw))...
    

    然后做:

    function redraw() {
      trans = d3.event.translate;
      scale = d3.event.scale;
      vis.selectAll("some_classname").attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
    }
    

  2. 或者您可以为所有不想触发缩放的元素添加一个类,然后使用 CSS3 :not pseudo-class:

    function redraw() {
      trans = d3.event.translate;
      scale = d3.event.scale;
      vis.selectAll("*:not(.some_classname)").attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
    }
    

【讨论】:

    【解决方案2】:

    我能找到的唯一解决方案是“丑陋的黑客”,例如,如果(我假设你是)你试图不缩放线条,你应该尝试下面的方法,它适用于放大和缩小:

    演示:http://jsfiddle.net/SO_AMK/gJMTb/

    JavaScript:

    function redraw() {
      vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
      vis.attr("font-size", (nodeFontSize / d3.event.scale) + "px");
      vis.selectAll("line.link").style("stroke-width", getStrokeWidth); // Function so it runs for each element individually
    }
    
    function getStrokeWidth(){
        if (!this.__data__.stroke) { // Doesn't exist, so set it to the original stroke-width
            this.__data__.stroke = parseFloat(d3.select(this).style("stroke-width"));
            // I found __data__ to be easier than d3's .data()
        }
        return this.__data__.stroke / d3.event.scale + "px";
    }
    

    请参阅documentation 了解有关使用style() 的功能的详细信息

    【讨论】:

    • 但是,我不确定我是否真的明白这里发生了什么......在函数getStrokeWidth 中,引用this 指向SVG 线元素,对吗?因此\_\_data\_\_ 属性指向使用 D3 添加的实际数据元素(图边)。但这与中风有什么关系?不是在 SVG 元素上而不是在数据元素上定义了笔画吗?
    • 一旦更改了stroke-width 值,就不能将其乘以d3.event.scale,因为(d3.event.scale) 它不是一个相对值。因此,我将原始 stroke-width 值缓存在元素 __data__ 对象中,以便稍后运行计算。您可以在值上使用console.log() 以查看发生了什么更好的情况。
    • 忘了说,__data__ 是 D3 的.data() 用来存储东西的,所以你也可以通过.data() 检索它。但是,这会创建一些额外的对象,并且不会让它变得更容易。
    猜你喜欢
    • 2021-04-07
    • 2017-11-26
    • 2019-08-06
    • 2013-12-23
    • 2018-12-05
    • 1970-01-01
    • 2015-06-21
    • 2021-12-29
    • 2015-01-18
    相关资源
    最近更新 更多