westcoast_509
westcoast_509

Reputation: 332

How to keep text from running over svg in responsive design?

I am trying to make a responsive page with an SVG and some text. Basically I would like the SVG to appear on the left side of the page, and the header and paragraph to appear on the right until the viewing window becomes too small and then to have the elements stack (in the order of: header, paragraph, svg).

I have two problems right now: 1. The header and text run on top of the svg (click on a node in the fiddle below to get the paragraph text to appear). 2. When the viewing window becomes very small, the text seems to disappear off the left side of the browser.

Here’s the jsfiddle: http://jsfiddle.net/westcoast_509/xgafy1to/

And here's the javascript:

var diameter = 960;

var tree = d3.layout.tree()
    .size([360, diameter / 2 - 200])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

var diagonal = d3.svg.diagonal.radial()
    .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

d3.select("body").append("div")
  .attr("class", "wrapper")

var svg = d3.select(".wrapper").append("svg")
    .attr("viewBox", "0 0 1500 1500")
    .attr("preserveAspectRatio", "xMinYMin meet")
    .attr('class', "cluster")
    .attr("width", diameter)
    .attr("height", diameter)
  .append("g")
    .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")")
    .style("float", 'left');

d3.json("https://api.myjson.com/bins/589z2", function(error, root) { 

  var nodes = tree.nodes(root),
      links = tree.links(nodes);

  var link = svg.selectAll(".link")
      .data(links)
    .enter().append("path")
      .attr("class", "link")
      .attr("d", diagonal);

 var titleBox = d3.select(".wrapper").append('div', ":first:child")
    .attr('class', 'titleBox')
    .text('Female Humans Amidst Fauna');

  var tooltip = d3.select(".titleBox").append("div")
    .attr('class', 'tooltip')

  var node = svg.selectAll(".node")
      .data(nodes)
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
      .on("mouseover", mouseover) 
      .on('mouseout', mouseout)

      .on("click", function(d) {
          tooltip.transition()
            .ease('linear')
            .duration(2500)  
            .style('opacity', 1)
              .each(function() {
                d3.selectAll('.div').transition()
                  .delay(4000)
                  .duration(2000)
                  .style('opacity', 0)
                  .remove();
              })


          var word = d.word

          tooltip.html(d.beginContext + " " + "<span class='keyword'>" + word + "</span>" + " " + d.endContext);
            //.remove();

      });


  node.append("circle")
      .attr("r", 4.5);

  node.append("text")
      .attr("dy", ".31em")
      .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
      .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
      .text(function(d) { return d.name; });

});

var chart = $(".cluster"),
    aspect = chart.width() / chart.height(),
    container = chart.parent();
$(window).on("resize", function() {
    var targetWidth = container.width();
    chart.attr("width", targetWidth);
    chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");

function mouseover() { //makes the text size increase on mouseover
  d3.select(this).select("text").transition()
    .duration(750)
    .style("font-size", "40px");

 }

function mouseout() { //returns text to original size
 d3.select(this).select("text").transition()
    .duration(750)
    .style("font-size", "15px");

 }

And here's the CSS:

.wrapper {
  display: inline-block;
  position: relative;
  width: 100%;
  padding-bottom: 100%; 
  vertical-align: top; 
  overflow: hidden; 

}

.node circle {
  fill: #fff;
  stroke: #41F9D0;
  stroke-width: 1.5px;
}

.link {
  fill: none;
  stroke: #41F9D0;
  stroke-width: 1.5px;
}

.keyword {
  font-size: 3vw;
  color: red;
}

.titleBox {
  display: inline-block;
  font-size: 5vw;
  position: absolute;
  width: 500px;
  top: 50;
  right: 0;
  margin-top: 5vw;
  float: left;
}

.tooltip {
  position: absolute;
  width: 400px;
  font-family: serif;
  opacity: 0;
  font-size: 2vw;
  margin-top: 50px;

}

.cluster {
  display: inline-block;
  position: absolute;
  top: 0;
  left: 0;
}

I’m still quite new to CSS/JS, so I appreciate any tips or pointers you might have!

Upvotes: 2

Views: 658

Answers (1)

daniman
daniman

Reputation: 284

I edited your fiddle to adhere to your requests: http://jsfiddle.net/7tzrrpvr/. I hope that's what you wanted!

The reason your svg was overlaying the text is because of your use of absolute positioning. Be careful with this, as setting a div to position: absolute takes it out of the normal flow of the DOM and will effectively make it invisible to its neighbours. Additionally, your titleBox was being dynamically created after the svg, which puts it in a lower position in the DOM. I moved this up in the javascript so that it will be created before the svg.

I added a media query in your css to achieve the responsive effect of stacking the columns for small viewports. Twitter Bootstrap (http://getbootstrap.com/) is a great library that uses media queries to do this for you automatically -- I recommend looking into that if you're planning to go further with responsive design in your app.

Upvotes: 3

Related Questions