Skip to content

Instantly share code, notes, and snippets.

@milkbread
Last active March 11, 2018 01:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save milkbread/6571949 to your computer and use it in GitHub Desktop.
Save milkbread/6571949 to your computer and use it in GitHub Desktop.
TextFitting

#Fitting Text into a Box

This is a JavaScript implementation for some simple code that:

  • scales,
  • wraps or
  • scales & wraps

text into a box of given/limited dimensions!

This demonstration is build with and depends on D3.js.

The complete code of the corresponding text_object can be found in the linked JS-library: text_object.js

<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="text_object.js"></script>
<title>Fitting Text into a Box</title>
<style>
#box{
fill:none;
stroke:#000;
stroke-width:2;
text-anchor="start";
}
#svg_container{
display:block;
}
.info{
background-color:#ccc;
display:inline-block;
vertical-align:top;
}
p{
font-size:25px;
margin:5px;
}
</style>
</head>
<body>
<h1>Fitting Text into a Box</h1>
<div class='info'>
<p>Main attributes</p>
<input name='text' id='width' size=5 value=300 onChange='run()'>Width</input>
<input name='text' id='height' size=5 value=300 onChange='run()'>Height</input>
<input name='text' id='fontSize' size=5 value=50 onChange='run()'>FontSize (pt)</input>
</div>
<div class='info'>
<p>Text attributes</p>
<input name='text' id='text_input' size=35 placeholder='Type in any text!' onChange='run()'>Input</input><br>
<input type="checkbox" id='scale_trans' name="scale_trans" onChange='run()'>Scale (Transform)</input><br>
<input type="checkbox" id='wrap_c' name="wrap_c" onChange='run()'>Wrap</input><br><br>
<input type="checkbox" id='scale' name="scale" onChange='run()'>Scale FontSize only (!NO other options available!)</input>
</div>
<div>
<p>Output:</p>
<svg id='svg_container'></svg>
</div>
</body>
<script>
//initialize all interactive elements using D3.js
//*******
var svg = d3.select('#svg_container');
var box = {x:d3.select('#width').attr('value'),y:d3.select('#height').attr('value'),offset:0}
var rect = svg.append('rect').attr('x',box.offset).attr('y',box.offset).attr('height',box.y).attr('width',box.x).attr('id','box')
var text_rep = svg.append('text').attr('id','text_rep').attr('x',0).attr('y',0).attr('text-anchor',"start");
var itp = d3.select('#text_input').attr('value','ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz');
var iwp = d3.select('#width');
var ihp = d3.select('#height');
var ifsp = d3.select('#fontSize');
var csp_f = d3.select('#scale');
var csp_t = d3.select('#scale_trans');
var cwp_c = d3.select('#wrap_c');
var cwp_cNs = d3.select('#wrap_cNS');
var text = new text_object(text_rep);
//*******
//Visualise initial output
run();
//main function for interactions
function run(){
//define the box
box = {x:iwp.node().value,y:ihp.node().value,offset:0}
console.log(iwp.node().value)
svg.attr('height',box.y).attr('width',box.x);
rect.attr('x',box.offset).attr('y',box.offset).attr('height',box.y).attr('width',box.x).attr('id','box')
//define the values of the text object
text.setContent(itp.node().value);
text.resetText(ifsp.node().value);
//scale only the font size ... this is cannot be combined with other options!
if(csp_f.node().checked==true){
csp_t.node().checked=false;
cwp_c.node().checked=false;
text.scaleFontSizeToBox(box.x, box.y);
}
//differentiation between...scaling the text...
if(csp_t.node().checked==true && cwp_c.node().checked==false){
text.scale(box.x, box.y);
}
//wrapping the text, or...
else if(cwp_c.node().checked==true && csp_t.node().checked==false){
text.wrap(box.x);
}
//...scale and wrap the text
else if (cwp_c.node().checked==true && csp_t.node().checked==true){
text.wrap_and_scale(box.x, box.y);
}
}
</script>
</html>
//!!!Getting the width and height from the d3.node() attribute does not work in Firefox
//!!!USE: document.getElementById("dummy_text").getBBox() for the measurements!!!
function text_object(text_rep){
//initial variables
this.str_ = '', this.font_size = 20, this.text_object = text_rep, this.scale_=null, this.dy = '.88em';
var text_height=0, text_width =0, lines = 1;
//BASIC FUNCTIONS
//+++++++++++++++
this.setContent = function(content){
this.str_ = content;
this.text_object.text(this.str_)
}
this.getContent = function(){return this.str_}
this.getFontSize = function(){return this.font_size}
this.getHeight = function(){return text_height}
this.setFontSize=function(fontsize){
this.font_size = fontsize;
this.text_object.attr('font-size',this.font_size+'pt').attr('dy',this.dy)
this.check_text_dimensions();
}
//+++++++++++++++
//TRANSFORMING FUNCTIONS
//+++++++++++++++
this.scale=function(width_, height_){
//get the scaling parameters
this.scale_ = this.getScale(width_, height_);
//transform (scale) svg-text element
this.text_object.attr('transform',"scale("+this.scale_.a+","+this.scale_.b+")");
}
this.wrap=function(width){
var total_ = 0, counter = 1;
//get an array - representation of the text
var raw_text = this.str_.split('');
//select the svg container
var svg_ = d3.select('svg');
//for each letter in the array
for(var i =0; i<raw_text.length; i++){
//dummy svg-text element, to...
var letter = svg_.append('text').attr('font-size',this.font_size+'pt').attr('id','dummy_text').text(this.str_[i]);
//...get the size of each letter-representation
total_=total_ + document.getElementById("dummy_text").getBBox().width; //letter.node().clientWidth;
//if the letters are too long for the box...
if(total_>=width){
total_=0; //...reset total length
counter = counter +1;
raw_text.splice(i,0,'_') //...add a separator
}
//remove the dummy svg-text element
letter.remove();
}
//make a STRING of the 'text array'
var text_='';
raw_text.forEach(function(d){text_=text_+d;})
//wrap the visual representation of the text
this.wrapTextObject(text_);
lines = counter;
}
this.wrapTextObject=function(content){
//split the text at the separator
var t_wrapped = content.split('_');
//loop the parts
if(t_wrapped.length>1){
//the first line is 'our' normal svg-text element
text_rep.text(t_wrapped[0])
//all following lines are a svg-text-tspan element
for(var i=1;i<t_wrapped.length;i++){
this.text_object.append('tspan').attr('x',0).attr('dy','.85em').attr('y',text_height*i).text(t_wrapped[i])
}
}
}
this.wrap_and_scale=function(box_){
//1st...wrap it
this.wrap(box.x);
//2nd...scale it
this.scale(box.x, box.y);
}
this.scaleFontSizeToBox=function(width_, height_){
//get the scaling parameters
this.scale_ = this.getScale(width_, height_);
//scale font size to scaling parameter a
this.setFontSize(this.font_size * this.scale_.a);
}
this.resetText=function(fontsize){
this.text_object.attr('transform',"scale(1,1)");
this.setFontSize(fontsize);
}
//+++++++++++++++
//CALCULATING FUNCTIONS
//+++++++++++++++
this.check_text_dimensions = function(){
text_width = document.getElementById("text_rep").getBBox().width; //this.text_object.node().offsetWidth;
text_height = document.getElementById("text_rep").getBBox().height; //this.text_object.node().offsetHeight;
}
this.getScale=function (width_, height_){
this.check_text_dimensions();
var a = width_/text_width;
var b = height_/text_height;
return {a:a, b:b};
}
}
@sciotta
Copy link

sciotta commented Jun 10, 2015

Great!!! The only thing can do here is remove the D3.js dependency. But you JS it's pretty awsome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment