在Rails 4上实现力导向图的鱼眼(使用d3.js)

时间:2013-12-12 22:13:58

标签: javascript jquery ruby-on-rails d3.js

我正在尝试使用d3.js在力导向图上实现鱼眼失真。由于某种原因,失真在链路上起作用,但在节点上起作用。这可能是由于节点是g元素引起的,但我不确定。任何帮助将不胜感激!

var svg, node, link;

function make_graph() {

  // Clear out the div first
  $("#display_graph svg:first").remove();

  // Sets size
  var width = 960,
      height = 500;

  // Maps groups to colors
  var color = d3.scale.category20();

  // Select the div and append a svg
  svg = d3.select("#display_graph").append("svg")
      .attr("width", width)
      .attr("height", height);

  // Pull json from graph
  var json_from_db = $('.graph_json').data('json');
  var json_nodes = json_from_db.nodes
  var json_links = json_from_db.links

  // Sets up the force directed graph
  var charge_val = $('#charge').val();
  var link_distance_val = $('#link_distance').val();
  var force = d3.layout.force()
      .charge(charge_val)
      .linkDistance(link_distance_val)
      .size([width, height])
      .nodes(json_nodes)
      .links(json_links)
      .start();

  link = svg.selectAll(".link")
      .data(json_links)
    .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var font_size_px = $('#font_size').val();
  node = svg.selectAll(".node")
      .data(json_nodes)
    .enter().append("g")
      .attr("class", "node")
      .style("font-size", font_size_px)
      .call(force.drag);

  var radius = $('#radius').val();
  node.append("circle")
      .attr("r", radius)
      .style("fill", function(d) { return color(d.group); });

  node.append("text")
      .attr("dx", 12)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

  force.on("tick", function() {
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });
    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
  });

  $('#fisheye_btn').click( function() {
    var glyph_color = $(this).css('color');
    // original color is white
    orig_color = 'rgb(255, 255, 255)';

    if (glyph_color == orig_color) {
      $(this).css('color', 'orange');
    } else {
      $(this).css('color', orig_color);
    };
  });

};

function make_fisheye() {
  var fisheye = d3.fisheye.circular()
    .radius(200)
    .distortion(2);

  svg.on("mousemove", function() {
    fisheye.focus(d3.mouse(this));

    node.each(function(d) { d.fisheye = fisheye(d); })
        .attr("cx", function(d) { return d.fisheye.x; })
        .attr("cy", function(d) { return d.fisheye.y; })
        .attr("r", function(d) { return d.fisheye.z * 4.5; });

    link.attr("x1", function(d) { return d.source.fisheye.x; })
        .attr("y1", function(d) { return d.source.fisheye.y; })
        .attr("x2", function(d) { return d.target.fisheye.x; })
        .attr("y2", function(d) { return d.target.fisheye.y; });
  });
}

最终,我希望用户能够通过单击按钮打开或关闭失真。谢谢你的帮助!

我更新了代码。我现在可以通过点击按钮打开或关闭失真。

// Make force directed graph on button click
$(document).ready( function() {
  $("#refresh_btn").click( function() {
    make_graph();
  });
});

// Turn on and off fisheye distortion
$(document).ready( function() {
  $('#fisheye_btn').click( function() {
    var glyph_color = $(this).css('color');
    // original color is white
    orig_color = 'rgb(255, 255, 255)';

    if (glyph_color == orig_color) {
      $(this).css('color', 'orange');
      make_graph();
      make_fisheye();
    } else {
      $(this).css('color', orig_color);
      make_graph();
    };
  });
});

var svg, node, link;

function make_graph() {

  // Clear out the div first
  $("#display_graph svg:first").remove();

  // Sets size
  var width = 960,
      height = 500;

  // Maps groups to colors
  var color = d3.scale.category20();

  // Select the div and append a svg
  svg = d3.select("#display_graph").append("svg")
      .attr("width", width)
      .attr("height", height);

  // Pull json from graph
  var json_from_db = $('.graph_json').data('json');
  var json_nodes = json_from_db.nodes
  var json_links = json_from_db.links

  // Sets up the force directed graph
  var charge_val = $('#charge').val();
  var link_distance_val = $('#link_distance').val();
  var force = d3.layout.force()
      .charge(charge_val)
      .linkDistance(link_distance_val)
      .size([width, height])
      .nodes(json_nodes)
      .links(json_links)
      .start();

  link = svg.selectAll(".link")
      .data(json_links)
    .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var font_size_px = $('#font_size').val();
  node = svg.selectAll(".node")
      .data(json_nodes)
    .enter().append("g")
      .attr("class", "node")
      .style("font-size", font_size_px)
      .call(force.drag);

  var radius = $('#radius').val();
  node.append("circle")
      .attr("r", radius)
      .style("fill", function(d) { return color(d.group); });

  node.append("text")
      .attr("dx", 12)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

  force.on("tick", function() {
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });
    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
  });
};

function make_fisheye() {
  var fisheye = d3.fisheye.circular()
    .radius(200)
    .distortion(2);

  svg.on("mousemove", function() {
    fisheye.focus(d3.mouse(this));

    node.each(function(d) { d.fisheye = fisheye(d); })
        .attr("cx", function(d) { return d.fisheye.x; })
        .attr("cy", function(d) { return d.fisheye.y; })
        .attr("r", function(d) { return d.fisheye.z * 4.5; });

    link.attr("x1", function(d) { return d.source.fisheye.x; })
        .attr("y1", function(d) { return d.source.fisheye.y; })
        .attr("x2", function(d) { return d.target.fisheye.x; })
        .attr("y2", function(d) { return d.target.fisheye.y; });
  });
}

不幸的是,我仍然遇到链接被扭曲的问题。节点实际上是g元素,我越来越相信可能是问题。有没有办法使用d3.js选择g元素内的元素?我很惊讶鱼眼扭曲不仅仅传递给g元素内部的元素。也许我猜错了?

新代码

现在点击按钮时节点和链接都会失真!这是代码:

// Global variables
var svg, node, link; 
var fisheye_on = false;

// Make force directed graph on button click
$(document).ready( function() {
  $("#refresh_btn").click( function() {
    // Make sure fisheye is turned off
    $('#fisheye_btn').css('color', 'white');
    fisheye_on = false;
    make_graph();
  });
});

// Turn on and off fisheye distortion
$(document).ready( function() {
  $('#fisheye_btn').click( function() {
    var glyph_color = $(this).css('color');
    // original color is white
    orig_color = 'rgb(255, 255, 255)';

    if (glyph_color == orig_color) {
      $(this).css('color', 'orange');
      fisheye_on = true;
      make_graph();
    } else {
      $(this).css('color', orig_color);
      fisheye_on = false;
      make_graph();
    };
  });
});


function make_graph() {

  // Clear out the div first
  $("#display_graph svg:first").remove();

  // Sets size
  var width = 960,
      height = 500;

  // Maps groups to colors
  var color = d3.scale.category20();

  // Select the div and append a svg
  svg = d3.select("#display_graph").append("svg")
      .attr("width", width)
      .attr("height", height);

  // Pull json from graph
  var json_from_db = $('.graph_json').data('json');
  var json_nodes = json_from_db.nodes
  var json_links = json_from_db.links

  // Sets up the force directed graph
  var charge_val = $('#charge').val();
  var link_distance_val = $('#link_distance').val();
  var force = d3.layout.force()
      .charge(charge_val)
      .linkDistance(link_distance_val)
      .size([width, height])
      .nodes(json_nodes)
      .links(json_links)
      .start();

  link = svg.selectAll(".link")
      .data(json_links)
    .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var font_size_px = $('#font_size').val();
  node = svg.selectAll(".node")
      .data(json_nodes)
    .enter().append("g")
      .attr("class", "node")
      .style("font-size", font_size_px)
      .call(force.drag);

  var radius = $('#radius').val();
  node.append("circle")
      .attr("r", radius)
      .style("fill", function(d) { return color(d.group); });

  node.append("text")
      .attr("dx", 12)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

  if (fisheye_on == false) {

    force.on("tick", function() {
      link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });
      node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    });

  } else {

    var fisheye = d3.fisheye.circular()
      .radius(200)
      .distortion(2);

    svg.on("mousemove", function() {
      fisheye.focus(d3.mouse(this));

      node.each(function(d) { d.fisheye = fisheye(d); });

      node.selectAll("circle")
          .attr("cx", function(d) { return d.fisheye.x - d.x; })
          .attr("cy", function(d) { return d.fisheye.y - d.y; })
          .attr("r", function(d) { return d.fisheye.z * 4.5; });

      node.selectAll("text")
          .attr("dx", function(d) { return d.fisheye.x - d.x; })
          .attr("dy", function(d) { return d.fisheye.y - d.y; });

      link.attr("x1", function(d) { return d.source.fisheye.x; })
          .attr("y1", function(d) { return d.source.fisheye.y; })
          .attr("x2", function(d) { return d.target.fisheye.x; })
          .attr("y2", function(d) { return d.target.fisheye.y; });
    });
  };
};

不幸的是,我遇到了另一个问题。应用失真时似乎存在初始延迟。节点首先失真,然后链接失真。不确定是什么导致了这一点。任何提示?

公开JSFiddle

我设法在公共JSFiddle中复制了这个问题:

http://jsfiddle.net/cspears2002/vVL99/

要制作图表,只需点击“制作图表”即可。点击“Fisheye”将打开和关闭鱼眼失真。问题是节点首先失真然后链接跟随。我希望节点和链接同时失真。任何帮助将不胜感激!

0 个答案:

没有答案