d3.js limit panning in force layout
Asked Answered
D

1

1

I am using d3.js with a force layout to visualize a large number of nodes. I would like to implement a limitation to the panning option of the zoom. JSFiddle : https://jsfiddle.net/40z5tw8h/24/

The above fiddle contains a simple version of what I am working on. Because I would potentially have to visualize a very large dataset, I use a function to scale down the group holding element ('g') after forces are done. In that way i always have the full visualization visible afterwards.

I would like to limit the panning - when the graph is fully visible, to only be able to move it within the viewport. In case the layout is zoomed, I would like to limit the panning as follows:

The group holding element should not be able to go:

  1. down more than 20 px from the top of the svg.
  2. right more than 20 px from the left side of the svg.
  3. up more than 20 px from the bottom of the svg.
  4. left more than 20 px from the right side of the svg.

I think all the implementation should be within the zoom function, which for now is:

function zoomed(){
        if (d3.event.sourceEvent == null){ //when fitFullGraph uses the zoom
            g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
        }
        else{
            var gElementBounds = g.node().getBoundingClientRect();
            var g_bottom = gElementBounds.bottom;
            var g_top = gElementBounds.top;
            var g_left = gElementBounds.left;
            var g_right = gElementBounds.right;
            var g_height = gElementBounds.height;
            var g_width = gElementBounds.width;

            var svg = g.node().parentElement;
            var svgElementBounds = svg.getBoundingClientRect();
            var svg_bottom = svgElementBounds.bottom;
            var svg_top = svgElementBounds.top;
            var svg_left = svgElementBounds.left;
            var svg_right = svgElementBounds.right;
            var svg_height = svgElementBounds.height;
            var svg_width = svgElementBounds.width;

            var t = d3.event.translate;
            var margin = 20;

            if(d3.event.sourceEvent.type == 'wheel'){//event is zoom
                g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");

            }
            else{//event is pan
                // if(t[0] < svg_left + margin) t[0]= svg_left + margin;
                //else if(t[0] > svg_width-g_width - margin) t[0] = svg_width-g_width - margin;
                // if(t[1] < g_height +margin) t[1] = g_height + margin;
                //else if (t[1] > svg_height - margin) t[1] = svg_height - margin;
               //.attr("transform", "translate(" + t+ ")scale(" + d3.event.scale + ")");
               //3.event.translate = t;
                g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
            }

        }

    }

The limitations I tried to implement are commented out, because they do not work properly.

Does anyone have a solution?

Decretive answered 20/10, 2016 at 13:57 Comment(0)
P
1

This is not the complete answer to your question.

I used for block panning to left side translate X scale

var translate = d3.event.translate;
var translateX = translate[0];
var translateY = translate[1];
var scale = d3.event.scale;
var tX = translateX * scale;
var tY = translateY * scale;
console.log('tx', tX, 'ty', tY);
// Do not pan more to left
if (tX> 0) {
  g.attr("transform", "translate(" + d3.event.translate + ")  scale(" + d3.event.scale + ")");
} else {
  translate[0] = 0;
  g.attr("transform", "translate(" + translate + ")  scale(" + d3.event.scale + ")");
}

Which cancels the translation to left but internally it continues. Your user probably stops dragging to the left. Panning to the right gets weird when starting to pan as internally the event has panned far to the left.

Pun answered 26/10, 2016 at 10:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.