最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - D3 Zoom with Scrollbars used as panning, Scrollbar width and height adjusts to zoom scale - Stack Overflow

programmeradmin1浏览0评论

I want to create the following:

  1. Make a dynamic graph

  2. It is Zoomable (Zooms at the center of currently seen display) (Zoom when certain buttons are clicked, mouse wheel are disabled for zoom)

  3. Elements are draggable (When dragged it is not affected by force graph arrangement) (When elements are dragged outside of the svg the svg grows in size)

  4. It has Scrollbar used as pan

So far I am already successful with

  1. Creating a force graph
  2. Creating zoom
  3. Elements are already draggable and not included in force after dragged
  4. Scrollbar also

I have two problems with these bination items:

  1. Having dragged elements, it is not included in force graph anymore. Which would lead to possible overlap of other elements if new ones.
  2. Scrollbar with zoom is not working wonders, when you zoom->scroll->zoom it zooms at the old location where the first zoom happened.

I would really need help for these two problems. I have not seen any example for zoom and scrollbar bination.

Here is the code.

function drawGraph(Data){
setDefault();

svg = d3.select("#graphingArea").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .call(zoom)
  .on("dblclick.zoom", false)
  .on("mousewheel.zoom", false)
  .on("DOMMouseScroll.zoom", false) // disables older versions of Firefox
  .on("wheel.zoom", false); // disables newer versions of Firefox;

//Needed for canvas to be dragged
rect = svg.append("rect")
  .attr("width", width)
  .attr("height", height)
  .style("fill", "none")
  .style("pointer-events", "all");

//Holds all that is to be dragged by the canvas
container = svg.append("g");

//Call zoom before drawing
svg.call(zoomUpdate);

//FOR DRAG
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);

//Creating data that is drawn
populateD3Data(container, drag);

// Set data to be Force Arranged
force = self.force = d3.layout.force()
.nodes(nodes)
.links(links)
.distance(150)
.charge(-1000)
.size([width,height])
.start();

//Event to call arrange
force.on("tick", tick);
}

Zooming js:

var zoom = d3.behavior.zoom()
    .scaleExtent([zoom_min_scale, zoom_max_scale])
    .on("zoom", zoomed);

function zoomed() {
  if(container != null && container != undefined) {
      var translate = zoom.translate(),
      scale = zoom.scale();

      tx = Math.min(0, Math.max(width * (1 - scale), translate[0]));
      ty = Math.min(0, Math.max(height * (1 - scale), translate[1]));

      zoom.translate([tx, ty]);
      container.attr("transform", "translate(" + [0,0] + ")scale(" + zoom.scale() + ")");

      svg.attr("width", AreaWidth_ * zoom.scale());
      svg.attr("height", AreaHeight_ * zoom.scale());

      $("#graphingArea").scrollLeft(Math.abs(zoom.translate()[0]));
      $("#graphingArea").scrollTop(Math.abs(zoom.translate()[1]));
  }
}

//Button event for zoom in
d3.select("#zoom_in")
    .on("click", zoomInOrOut);

//Button event for zoom out
d3.select("#zoom_out")
    .on("click", zoomInOrOut);

//Gets the center of currently seen display
function interpolateZoom (translate, scale) {
    return d3.transition().duration(1).tween("zoom", function () {
        var iTranslate = d3.interpolate(zoom.translate(), translate),
            iScale = d3.interpolate(zoom.scale(), scale);
        return function (t) {
            zoom
                //Round number to nearest int because expected scale for now is whole number
                .scale(Math.floor(iScale(t)))
                .translate(iTranslate(t));
            zoomed();
        };
    });
}

function zoomInOrOut() {
    var direction = 1,
        target_zoom = 1,
        center = [graph_area_width / 2, graph_area_height / 2],
        extent = zoom.scaleExtent(),
        translate = zoom.translate(),
        translate0 = [],
        l = [],
        view = {x: translate[0], y: translate[1], k: zoom.scale()};

    d3.event.preventDefault();
    direction = (this.id === 'zoom_in') ? 1 : -1;
    target_zoom = zoom.scale() + (direction * zoom_scale);

    if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }

    translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
    view.k = target_zoom;
    l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];

    view.x += center[0] - l[0];
    view.y += center[1] - l[1];

    interpolateZoom([view.x, view.y], view.k);
}

function zoomUpdate() {
    var target_zoom = 1,
    center = [graph_area_width / 2, graph_area_height / 2],
    extent = zoom.scaleExtent(),
    translate = zoom.translate(),
    translate0 = [],
    l = [],
    view = {x: translate[0], y: translate[1], k: zoom.scale()};

    target_zoom = zoom.scale();

    if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }

    translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
    view.k = target_zoom;
    l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];

    view.x += center[0] - l[0];
    view.y += center[1] - l[1];

    interpolateZoom([view.x, view.y], view.k);
}

I want to create the following:

  1. Make a dynamic graph

  2. It is Zoomable (Zooms at the center of currently seen display) (Zoom when certain buttons are clicked, mouse wheel are disabled for zoom)

  3. Elements are draggable (When dragged it is not affected by force graph arrangement) (When elements are dragged outside of the svg the svg grows in size)

  4. It has Scrollbar used as pan

So far I am already successful with

  1. Creating a force graph
  2. Creating zoom
  3. Elements are already draggable and not included in force after dragged
  4. Scrollbar also

I have two problems with these bination items:

  1. Having dragged elements, it is not included in force graph anymore. Which would lead to possible overlap of other elements if new ones.
  2. Scrollbar with zoom is not working wonders, when you zoom->scroll->zoom it zooms at the old location where the first zoom happened.

I would really need help for these two problems. I have not seen any example for zoom and scrollbar bination.

Here is the code.

function drawGraph(Data){
setDefault();

svg = d3.select("#graphingArea").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .call(zoom)
  .on("dblclick.zoom", false)
  .on("mousewheel.zoom", false)
  .on("DOMMouseScroll.zoom", false) // disables older versions of Firefox
  .on("wheel.zoom", false); // disables newer versions of Firefox;

//Needed for canvas to be dragged
rect = svg.append("rect")
  .attr("width", width)
  .attr("height", height)
  .style("fill", "none")
  .style("pointer-events", "all");

//Holds all that is to be dragged by the canvas
container = svg.append("g");

//Call zoom before drawing
svg.call(zoomUpdate);

//FOR DRAG
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);

//Creating data that is drawn
populateD3Data(container, drag);

// Set data to be Force Arranged
force = self.force = d3.layout.force()
.nodes(nodes)
.links(links)
.distance(150)
.charge(-1000)
.size([width,height])
.start();

//Event to call arrange
force.on("tick", tick);
}

Zooming js:

var zoom = d3.behavior.zoom()
    .scaleExtent([zoom_min_scale, zoom_max_scale])
    .on("zoom", zoomed);

function zoomed() {
  if(container != null && container != undefined) {
      var translate = zoom.translate(),
      scale = zoom.scale();

      tx = Math.min(0, Math.max(width * (1 - scale), translate[0]));
      ty = Math.min(0, Math.max(height * (1 - scale), translate[1]));

      zoom.translate([tx, ty]);
      container.attr("transform", "translate(" + [0,0] + ")scale(" + zoom.scale() + ")");

      svg.attr("width", AreaWidth_ * zoom.scale());
      svg.attr("height", AreaHeight_ * zoom.scale());

      $("#graphingArea").scrollLeft(Math.abs(zoom.translate()[0]));
      $("#graphingArea").scrollTop(Math.abs(zoom.translate()[1]));
  }
}

//Button event for zoom in
d3.select("#zoom_in")
    .on("click", zoomInOrOut);

//Button event for zoom out
d3.select("#zoom_out")
    .on("click", zoomInOrOut);

//Gets the center of currently seen display
function interpolateZoom (translate, scale) {
    return d3.transition().duration(1).tween("zoom", function () {
        var iTranslate = d3.interpolate(zoom.translate(), translate),
            iScale = d3.interpolate(zoom.scale(), scale);
        return function (t) {
            zoom
                //Round number to nearest int because expected scale for now is whole number
                .scale(Math.floor(iScale(t)))
                .translate(iTranslate(t));
            zoomed();
        };
    });
}

function zoomInOrOut() {
    var direction = 1,
        target_zoom = 1,
        center = [graph_area_width / 2, graph_area_height / 2],
        extent = zoom.scaleExtent(),
        translate = zoom.translate(),
        translate0 = [],
        l = [],
        view = {x: translate[0], y: translate[1], k: zoom.scale()};

    d3.event.preventDefault();
    direction = (this.id === 'zoom_in') ? 1 : -1;
    target_zoom = zoom.scale() + (direction * zoom_scale);

    if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }

    translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
    view.k = target_zoom;
    l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];

    view.x += center[0] - l[0];
    view.y += center[1] - l[1];

    interpolateZoom([view.x, view.y], view.k);
}

function zoomUpdate() {
    var target_zoom = 1,
    center = [graph_area_width / 2, graph_area_height / 2],
    extent = zoom.scaleExtent(),
    translate = zoom.translate(),
    translate0 = [],
    l = [],
    view = {x: translate[0], y: translate[1], k: zoom.scale()};

    target_zoom = zoom.scale();

    if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }

    translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
    view.k = target_zoom;
    l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];

    view.x += center[0] - l[0];
    view.y += center[1] - l[1];

    interpolateZoom([view.x, view.y], view.k);
}
Share Improve this question asked Oct 7, 2014 at 8:33 erwin limerwin lim 711 silver badge4 bronze badges 1
  • Did you get answer for it? As i am also trying to implement scrollbar with zoom. – Sneha Commented Mar 20, 2018 at 5:12
Add a ment  | 

1 Answer 1

Reset to default 7

Here is my take on bining d3-zoom with scrollbars: https://stackblitz./edit/d3-pan-and-zoom

Apart from handling d3's zoom to update scrollbar positions, you also need to handle scrolling with scrollbars to update d3's internal zoom representation by calling translateTo().

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论