How to achieve that bubbles are only clickable if completly zoomed d3js
Asked Answered
B

2

3

I have a little problem here:

I'm working with this example (http://bl.ocks.org/mbostock/7607535) and I modified the flare.json file like this:

{
  "name": "flare",
"children": [
{
"name": "Kommunikation und Umwelt",
"children": [

{
 "name": "Courses",
 "children": [
  {
   "name": "AO-Psy.",
   "children": [
    {"name": "Prof. A", "size": 5731,"url":"index.html"},
    {"name": "Prof. B", "size": 5731},
    {"name": "Prof. C", "size": 5731}
   ]
  },
  {
   "name": "E&E",
   "children": [
    {"name": "Prof. D", "size": 5731},
    {"name": "Prof. E", "size": 5731},
    {"name": "Prof. F", "size": 5731},
    {"name": "Prof. G", "size": 5731},
    {"name": "Prof. H", "size": 5731}
   ]
  },
  {
   "name": "IBSS",
   "children": [
    {"name": "Prof. I", "size": 5731},
    {"name": "Prof. J", "size": 5731},
    {"name": "Prof. K", "size": 5731}
   ]
  },
  {"name": "", "size": 0},
  {
   "name": "E-Gov",
   "children": [
    {"name": "Prof. L", "size": 5731},
    {"name": "Prof. M", "size": 5731},
    {"name": "Prof. N", "size": 5731}
   ]
  },
  {
   "name": "Muki",
   "children": [
    {"name": "Prof. O", "size": 5731},
    {"name": "Prof. P", "size": 5731},
    {"name": "Prof. Q", "size": 5731},
    {"name": "Prof. V", "size": 5731}
   ]
  },
  {"name": "Schedule", "size": 5731},
  {"name": "News", "size": 5731},
  {"name": "Events", "size": 5731},
  {"name": "Search", "size": 5731},
  {"name": "", "size": 0}
 ]
},
{"name": "", "size": 0}
]
},

If I click on Prof.A, I get my next html page. My problem is that I can click on Prof.A even when I haven't zoomed in on this bubble. I just want to be able to click on it when I have zoomed on it and the label is readable.

I tried to "fix" the zoom functions, but nothing seems to work.

zoom.html:

<!DOCTYPE html>    
<html xmlns:xlink="http://www.w3.org/1999/xlink">
<meta charset="utf-8">
<style>

.node {
cursor: pointer;
}

.node:hover {
stroke: #000;
stroke-width: 1.5px;
}

.node--leaf {
fill: #14DCD2;
}

.label {
 pointer-events: none;
 font: 20px "Helvetica Neue", Helvetica, Arial, sans-serif;
 text-anchor: middle;
 text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
 }

 .label,
 .node--root,
 .node--leaf {
 pointer-events: all;
 }
 .node--leaf:hover {
 fill: orangered;
 }

 </style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
 <script>


var margin = 600,
diameter = 1920;

var color = d3.scale.linear()
.domain([-1, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl);

var pack = d3.layout.pack()
.padding(2)
.size([diameter - margin, diameter - margin])
.value(function(d) { return d.size; })

var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

d3.json("flare.json", function(error, root) {
if (error) return console.error(error);

var focus = root,
  nodes = pack.nodes(root),
  view;

var circle = svg.selectAll("circle")
  .data(nodes)
.enter().append("circle")
  .attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
  .style("fill", function(d) { return d.children ? color(d.depth) : null; })
  .on("click", clickFct)

  function clickFct(d,i) {
  if (d3.select(this).classed("node--leaf")) {
    window.open(d.url,"_self"); //open URL here
  } else {
    if (focus !== d) 
    {
        zoom(d); 
        d3.event.stopPropagation();
    }
  }
  }

  var text = svg.selectAll("text")
  .data(nodes)
 .enter().append("text")
  .attr("class", "label")
  .style("fill-opacity", function(d) { return d.parent === root ? 1 : 0; })
  .style("display", function(d) { return d.parent === root ? null : "none"; })
  .text(function(d) { return d.name; })
  //.on('click', function(d, i) {window.location.href = d.url;});

  var node = svg.selectAll("circle,text")

  node.each(function(d){
  var thisNode = d3.select(this);
  if (!d.children) {
    thisNode.append("a")
        .attr("xlink:href", function(d) { return d.url; })
        .append("text")
            .attr("dx", 8)
            .attr("dy", 3)
            .attr("text-anchor", "start")
            .text(function(d) { return d.name; })
            ;
   } else {
    thisNode.append("text")
        .attr("dx", -8)
        .attr("dy", 3)
        .attr("text-anchor", "end")
        .text(function(d) { return d.name; });      
     }

    });




   d3.select("body")
  .style("background", color(-1))
  .on("dblclick", function() { zoom(root); });

   zoomTo([root.x, root.y, root.r * 2 + margin]);

   function zoom(d) {
   var focus0 = focus; focus = d;
   //.attr("xlink:href", url);
   //.on('click', function(d, i) {window.location.href = d.url;});

   var transition = d3.transition()
    .duration(d3.event.altKey ? 7500 : 750)
    .tween("zoom", function(d) {
      var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 4 + margin]);
      return function(t) { zoomTo(i(t)); };
    });

    transition.selectAll("text")
   .filter(function(d) { return d.parent === focus || this.style.display === "inline"; })
    .style("fill-opacity", function(d) { return d.parent === focus ? 1 : 0; })
    .each("start", function(d) { if (d.parent === focus) this.style.display = "inline"; })
    .each("end", function(d) { if (d.parent !== focus) this.style.display = "none"; });

    }

    function zoomTo(v) {
    var k = diameter / v[2]; view = v;
    node.attr("transform", function(d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
    circle.attr("r", function(d) { return d.r * k; });

    }

     });

     d3.select(self.frameElement).style("height", diameter + "px");

    </script>
    </html>

I cant make any progress nothing seems to work please help me!

Benthamism answered 14/1, 2015 at 16:54 Comment(2)
do you happen to have a jsfiddle?Christean
@PinguinDirk yes here jsfiddle.net/chroth/fkxcvtu9/3Benthamism
C
2

Let me expand a bit on @Elijah's answer:

First, I'd remove the following bit from the css:

.node--root,
.node--leaf {
  pointer-events: all;
}

in order to get more control over the pointer-events.

Next, we add some additional class to the nodes so that we can access these more easily:

.attr("class", function(d) { return 'depth' + d.depth + ' ' + 
  (d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"); })

Accordingly, every node has some additional class, like .depth4.

Now we can talk to the nodes, directly and add/remove the pointer-events as needed.

For that, and convenience, we add a new function:

function adjustPointerEvents(depth) {
  d3.selectAll('.node').attr('pointer-events', 'none');
  d3.select('.node--root').attr('pointer-events', 'all');
  d3.selectAll('.depth' + (depth + 1)).attr('pointer-events', 'all');
}

(first we remove all events, then we add the events to the node-root back (to be able to zoom out), and then we add the events for the 'next' level))

On init, we call that at level 2:

adjustPointerEvents(2);

By the way: you have some sort of an additional layer there ('Kommunikation und Umwelt' and then 'Courses'), I leave the fine tuning to you...

And we have to make sure we call that on click:

function clickFct(d,i) {
  adjustPointerEvents(d.depth);
  ...

And we're all set.

Here's the updated jsfiddle: Fiddle

As mentioned above, some fine tuning is still needed, but I hope I provided some more pointers.

Christean answered 1/2, 2015 at 11:35 Comment(0)
E
1

You can dynamically change the pointer-events style of the node based on the zoom level. So in your .enter() when the node is created set .style("pointer-events", "none") and then when that node is zoomed in, something like

d3.select("some css for identifying the node")
 .style("pointer-events", "auto")

Depending on how you're doing the zoom, this would need to be adjusted (for instance, if clicking on the node at first zooms it in and then after that clicking on the node opens the page, in which case you'd need to change the .on("click") behavior. If you want to avoid inline styles (and you should) you could have the base class of your nodes have pointer-events: none a class of clickable which has pointer-events: auto and you can use d3.classed("clickable", true) in your zoom function to make click behavior available.

Egger answered 14/1, 2015 at 19:32 Comment(2)
this doesnt seem to work now nothing is clickable and i cant zoom now maybe i did something wrongBenthamism
can you give me an example where to change everthing?Benthamism

© 2022 - 2024 — McMap. All rights reserved.