d3 how to tie text to top right corner of view port while zooming and panning

nb12345

I am creating a mapping application in d3 and want to tie some text to the top right corner of my view port. Additionally, I want the text to remain in the top right corner while I zoom and pan across the application.I think I can solve my problem by figuring out how to get the coordinates of the top right corner of my view. Knowing this information would allow me to then set the coordinates of my text element. I've tried manually setting the dimensions of the containing svg element and then moving the text to that location but interestingly this didn't work. I was hoping to be able to find the coordinates programatically rather than setting coordinates manually. How can I do this in d3/javascript?

EDIT: My code is a modification of this code by Andy Barefoot: https://codepen.io/nb123456/pen/zLdqvM

My own zooming and panning code has essentially remained the same as the above example:

function zoomed() {
  t = d3
    .event
    .transform
  ;
  countriesGroup
    .attr("transform","translate(" + [t.x, t.y] + ")scale(" + t.k + ")")
  ;
}

I'm trying to append the text at the very bottom of the code:

countriesGroup.append("text")
        .attr("transform", "translate(" How do I get top right coordinates? ")")
        .style("fill", "#ff0000")
        .attr("font-size", "50px")
        .text("This is a test");

My idea is to be able to get the top right coordinates of the view port through the code rather than setting it manually and then have the coordinates of the text update as the user zooms or pans.

Andrew Reid

To keep something in place while zooming and panning you could invert the zoom:

point == invertZoom(applyZoom(point))

This isn't particularly efficient, as we are using two operations to get to the original number. The zoom is applied here:

countriesGroup
  .attr("transform","translate(" + [t.x, t.y] + ")scale(" + t.k + ")");

While the inversion would need to look something like:

text.attr("x", d3.zoom.transform.invert(point)[0])
    .attr("y", d3.zoom.transform.invert(point)[1])
    .attr("font-size", baseFontSize / d3.zoom.transform.k);

Where point and base font size are the original anchor point and font size. This means storing that data somewhere. In the example below I assign it as a datum to the text element:

var width = 500;
var height = 200;

var data = d3.range(100).map(function() {
  return {x:Math.random()*width,y:Math.random()*height}
})

var zoom = d3.zoom()
  .on("zoom",zoomed);

var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height)
  .call(zoom);
  
var g = svg.append("g")

var circles = g.selectAll()
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("r", 5)
  .attr("fill","steelblue")
  

var text = g.append("text")
  .datum({x: width-10, y: 20, fontSize: 12})
  .attr("x", function(d) { return d.x; })
  .attr("y", function(d) { return d.y; })
  .style("text-anchor","end")
  .attr("font-size",function(d) { return d.fontSize; })
  .text("This is a test");
  
  
function zoomed() {
  g.attr("transform", d3.event.transform);
  
  var d = text.datum();
  var p = d3.event.transform.invert([d.x,d.y]);
  var x1 = p[0];
  var y1 = p[1];
  
  text.attr("x",x1)
    .attr("y",y1)
    .attr("font-size", d.fontSize / d3.event.transform.k)
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

Better Solution

The above is the solution to the approach you seem to be looking for. But the end result is best achieved by a different method. As I mention in my comment, the above approach goes through extra steps that can be avoided. There can also be some size/clarity changes in the text when zooming (quickly) using the above method

As noted above, you are applying the zoom here:

countriesGroup
    .attr("transform","translate(" + [t.x, t.y] + ")scale(" + t.k + ")")

The zoom transform is applied only to countriesGroup, if your label happens to be in a different g (and not a child of countriesGroup), it won't be scaled or panned.

We wouldn't need to apply and invert the zoom, and we wouldn't need to update the position or font size of the text at all.

var width = 500;
var height = 200;

var data = d3.range(100).map(function() {
  return {x:Math.random()*width,y:Math.random()*height}
})

var zoom = d3.zoom()
  .on("zoom",zoomed);

var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height)
  .call(zoom);
  
var g = svg.append("g");
var g2 = svg.append("g"); // order does matter in layering

var circles = g.selectAll()
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("r", 5)
  .attr("fill","steelblue")
  
// position once and leave it alone:
var text = g2.append("text")
  .attr("x", width - 10)
  .attr("y", 20 )
  .style("text-anchor","end")
  .attr("font-size", 12)
  .text("This is a test");
  
  
function zoomed() {
  // apply the zoom to the g that has zoomable content:
  g.attr("transform", d3.event.transform); 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to keep an image in the top right corner of my webpage when zooming in/out?

D3: keeping position of SVG's relative while panning and zooming

How to show Text at top right corner of Action bar in Android?

How to stop ScrollView from scrolling when panning/zooming on a MapBox view?

How can I detect panning and zooming by the user with d3 zoomBehavior?

How can I get the Temperature to display in the top left corner while having the time and date in the top right?

Having trouble panning and zooming on my d3 map

Constraining zooming and panning in a D3 map viewport

D3: Zooming/Panning Line Graph in SVG is not working in Canvas

D3 Canvas graph zooming and panning slow redraw in Webview

how to place button on top right corner of image

How to set DockWidget at Top Right corner of QGIS?

How to align two matplotlib text-boxes side-by-side in the top-right corner?

How to check if my Cytoscape.js graph is out of view (even partially) after panning and/or zooming?

How to remove the gizmo perspective icon on the top right corner in Unity 3d?

Why is there a "plus" icon at the top right corner of my view?

Display a text in right-top-corner of Bootstrap panel-body

How to set image position inside <td> tag to be on top-left corner while text is on the left-bottom

How to rotate text and pin to the right bottom corner?

D3 zoom is constantly zooming down and right of SVG, how do I fix this?

How to start text in the left top corner in TextFormField

Why is corner radius applied only to top left and right corner for a custom view?

How do I move hot corner thap opens Activities Overview from top left to top right corner?

d3 v2 Prevent Zooming and Panning Chart Outside Viewport

How do I align a div to the top right corner of my <img>?

How to start in top right corner of label (zebra label printer)

How does Nautilus populate the list with shortcuts in the top right corner?

How to have a close button on the top right corner in nativescript?

How to put the number at top right corner of cart icon?