Reputation: 9814
I am using SVG to draw text and shapes in D3.js, and want to draw shapes inline with text and with similar dimensions to the text. The only way I can think of doing this is draw a rect around each tspan then draw the shape in relative position to the tspan rect. The result being:
This is a rectangle [] this is a circle ()
Where the brackets above represent the SVG shapes. Current code is below.
js:
function setupSVG(){
d3.select("div#chartId")
.append("div")
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 200 200")
.attr("id", "svg_area_id")
}
function renderSVGText(){
var svgArea = d3.select("svg#svg_area_id");
svgArea.append("rect")
.attr("x", 100)
.attr("y", 0)
.attr("height", 10)
.attr("width", 10)
.attr("id", "shape");
var group = svgArea.append("g")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "red") //I only want to draw rect stroke
.style("fill", "none");
var text = group.append("text")
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.style('fill', 'black')
var tspan1 = text.append('tspan')
tspan1.text("This is a square");
var tspan2 = text.append('tspan')
tspan2.text("and this is a triangle");
var boundingRect = group.append("rect")
//see http://phrogz.net/SVG/tspan_bounding_box.xhtml
var bbox = tspan1.getBoundingClientRect();
var pt = svg.createSVGPoint();
pt.x = bbox.left;
pt.y = bbox.top;
var pt2 = pt.matrixTransform(xform);
rect.setAttribute('x',pt2.x);
rect.setAttribute('y',pt2.y);
pt.x = bbox.right;
pt.y = bbox.bottom;
pt = pt.matrixTransform(xform);
boundingRect.attr('width', pt.x-pt2.x);
boundingRect.attr('height',pt.y-pt2.y);
/* this draws a rect around all text
var textSize = text.node().getBBox();
boundingRect.attr("width", textSize.width)
.attr("height", textSize.height);
*/
}
html:
<div class="svg-container" id="chartId"></div>
css:
.svg-container {
display: inline-block;
width: 512px;
height: 512px;
padding-top: 50px;
padding-bottom: 100%; /* aspect ratio */
vertical-align: top;
overflow: hidden;
border: 1px solid black;
}
Any ideas on how to do this? Any easier ways than the track I am following?
Upvotes: 0
Views: 1110
Reputation: 9814
I tried to get tspan dimensions using tspan.node().getComputedTextLength() but this returned an error, I presume because it hadn't been rendered at the call time. I just used text.node().getBBox() to get each text blocks dimensions instead:
function renderSVGText(){
var svgArea = d3.select("svg#svg_area_id");
var group = svgArea.append("g")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "red")
.style("fill", "none");
var text = group.append("text")
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.attr("id", "text_id")
.style('fill', 'black');
var tspan1 = text.append('tspan')
.attr("id", "tspan1_id")
tspan1.text("This is a square");
var boundingRect = svgArea.append("rect")
.style("stroke", "pink")
.style("fill", "none");
var textSize = text.node().getBBox();
boundingRect.attr("width", textSize.width)
.attr("height", textSize.height);
svgArea.append("rect")
.attr("x", textSize.width+10)
.attr("y", 0)
.attr("height", textSize.height)
.attr("width", textSize.height)
.attr("id", "shape");
var text2 = group.append("text")
.attr("x", textSize.width+textSize.height+20)
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.attr("id", "text2_id")
.style('fill', 'black');
var tspan2 = text2.append('tspan')
tspan2.text("and this is a triangle");
}
Upvotes: 0