d3js center a triangle stacked over a textbox whose value changes dynamically

After creating the text, get its width with getBoundingClientRect. We can use node() in D3 on a selection to get the DOM node. Since the text is shifted to the right, we’ll shift it back using half the text width.

(The string with backticks is a template string).

const textWidth = TEXT.node().getBoundingClientRect().width
TEXT.attr("transform", `translate(${-textWidth/2}, ${(height / 2 + 75)})`);

const MARGIN = {
  LEFT: 80,
  RIGHT: 80,
  TOP: 30,
  BOTTOM: 30
};

const RECT_HEIGHT = 50,
  DOMAIN = [0, 14];

let width = $(window).width() - MARGIN.LEFT - MARGIN.RIGHT,
  height = $(window).height() - MARGIN.TOP - MARGIN.BOTTOM;

let value = 0,
  arrowPosition = 0;

const FORMAT = d3.format(".1f");

////////////////////////////////////////////////////////////
///////////////////////// SVG //////////////////////////////
////////////////////////////////////////////////////////////

const SVG = d3.select("#scale")
  .append("svg")
  .attr("width", width + MARGIN.LEFT + MARGIN.RIGHT)
  .attr("height", height + MARGIN.TOP + MARGIN.BOTTOM);

const G = SVG.append("g")
  .attr("transform", "translate(" + MARGIN.LEFT + "," + MARGIN.TOP + ")");

const RECT = G.append("rect")
  .attr("x", 0)
  .attr("y", height / 2 - (RECT_HEIGHT / 2))
  .attr("width", width)
  .attr("height", RECT_HEIGHT);

//Draw the triangle symbol
let triangle = d3.symbol().type(d3.symbolTriangle).size(300);
const TRIANGLE = G.append("path")
  .attr("d", triangle)
  .attr("transform", "translate(" + 0 + "," + (height / 2 + 40) + ")");

//pH text element 
const TEXT = G.append("text")
  .attr("id", "pH")
  .text(FORMAT(value))

const textWidth = TEXT.node().getBoundingClientRect().width

TEXT.attr("transform", `translate(${-textWidth/2}, ${(height / 2 + 75)})`);

////////////////////////////////////////////////////////////
//////////////////////// Scale /////////////////////////////
////////////////////////////////////////////////////////////

const SCALE = d3.scaleLinear()
  .domain([0, width])
  .range(DOMAIN);

////////////////////////////////////////////////////////////
///////////////////// Event handler ////////////////////////
//////////////////////////////////////////////////////////// 

RECT.on("mousemove", (event) => {
  let coordinates = d3.pointer(event);
  const textWidth = TEXT.node().getBoundingClientRect().width
  TRIANGLE.attr("transform", "translate(" + coordinates[0] + ", " + (height / 2 + 40) + ")");
  TEXT.attr("transform", `translate(${-textWidth/2 + coordinates[0]}, ${(height / 2 + 75)})`);
  TEXT.text(FORMAT(SCALE(coordinates[0])));
});
<div id="scale"></div>


<!--jQuery.js-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<!-- d3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js" integrity="sha512-I54fxhTJwRigWTc3uNjgDzgii7LW+WJuyyA8kc6WaaZ7RQQNAf8bOEJLRNav7n/ca09MUwl5FptUukvqrOTUvQ==" crossorigin="anonymous"></script>

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top