Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <head>
<!-- Fonts to load from fonts.google.com-->
<!-- Saira comes in 9 weights -->
<link href="https://fonts.googleapis.com/css?family=Saira:100,200,300,400,500,600,700,800,900" rel="stylesheet"> 
  
 <!-- Saira also comes in 4 widths -->
<link href="https://fonts.googleapis.com/css?family=Saira|Saira+Condensed|Saira+Extra+Condensed|Saira+Semi+Condensed" rel="stylesheet"> 
  
<!-- These fonts are fairly different from one another -->
<link href="https://fonts.googleapis.com/css?family=Aldrich|Arima+Madurai|Arvo|Henny+Penny|Indie+Flower|Libre+Baskerville|Pirata+One|Poiret+One|Sancreek|Satisfy|Share+Tech+Mono|Smokum|Snowburst+One|Special+Elite" rel="stylesheet"> 
</head>

<H2>Data-driven typographic attributes using D3.js</H2>

<p><small>Below are D3 examples, created using these attribute tags in SVG for various font attributes:
<ul>
<li> Color: <i>fill</i>
<li> Weight: <i>font-weight</i> Ranges from 100-900. Must be supported by specific font available to the page, e.g. fonts.google.com Saira has nine weights, load all nine to use them, see the header. See also "variable fonts".
<li> Oblique: to create variable oblique angles, use skewX() in a group-transformation applied to each text item
<li> Typeface: <i>font-family</i> First, load many typefaces in the header, then apply.
<li> Underline: <i>text-decoration</i> Set to <i>underline</i> to get an underline, but otherwise SVG provides very little control over underline style. Use <i>tspan</i> to limit the scope of the underline (or any other attribute). Note use of invisible characters to make the underline longer than the word. Unfortunately, inconsistent support across browsers.
<li> Width: <i>font-family</i> While there is a width attribute in SVG, get more consistent results by loading a font with many widths (e.g. Saira or a variable font with width axis). Then change the font to match the desired width. Use a D3 quantile scale instead of the case statement for more effective control. 
<li> Spacing: <i>letter-spacing</i> Tracking - i.e. the space between letters.
<li> Baseline: <i>dy</i> A list of dy offsets shift the letters up/down. Text on path could be used instead and is supported in SVG.  
<li> Outline: <i>stroke</i> and <i> stroke-width</i>. While feasible, tricky to use as the stroke widths can make the text hard to read - e.g. the counters (i.e. holes) tend to fill in making them blobby, such as the a in Ian and the e in Gem. 
<li> Combos: Any of the above can be combined together to create additional encodings. </ul>
A more detailed discussion of each of the attributes including characterization, encodings and examples are in the book <i>Visualizing with Text,</i> (Richard Brath, 2020, <a href='https://www.routledge.com/Visualizing-with-Text/Brath/p/book/9780367259266'>A.K.Peters</a>, <a href='https://www.amazon.com/Visualizing-Text-AK-Peters-Visualization-dp-0367259265/dp/0367259265/'>Amazon</a>).<br><p><b>
              
            
!

CSS

              
                		h2 {
			font-family: "Roboto Slab";
			font-weight: 700;
			color: #222277;
		}
              
            
!

JS

              
                // Some Data, Colors and Fonts:
data = ["Abe","Bev","Cam","Dan","Eve","Fay","Gem","Hui","Ian"];
clrs = ["red","brown","coral","goldenrod","maroon","olive","orchid","tomato","peru","plum","salmon","teal","tan","thistle","indigo","black","lime","aqua"];
fonts = ["Aldrich","Arima Madurai","Henny Penny","Indie Flower","Libre Baskerville","Pirata One","Sancreek","Satisfy","Share Tech Mono","Smokum","Snowburst One","Special+Elite","Arvo"]
    
// Create the SVG canvas:
var svg = d3.select("body").append("svg")
    .attr("width", 500)
    .attr("height", 270);
	
// Color text via fill:  
svg.append("text")
    .attr("x",10).attr("y",15).text("Color:")
svg.selectAll("clrtext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
	  .attr("y",15)
	  .attr("font-family", "Saira")
	  .attr("fill", function(d,i) {return clrs[i];})
	  .text( function(d) {return d;});
  
// Weight via svg font-weight. 
// Uses values from 100-900, depending on the font chosen. 
// See fonts.google.com for sample fonts and weights
// The font Saira has 9 weights 
svg.append("text")
    .attr("x",10).attr("y",35).text("Weight:")
svg.selectAll("boldtext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",35)
  	.attr("font-family", "Saira")
  	.attr("font-weight",function(d,i) {return i*100+100;})
  	.text( function(d) {return d;});

// Oblique angle via svg transform skewX() on a group, then append the text
svg.append("text")
    .attr("x",10).attr("y",55).text("Oblique:")
obliquetext = svg.selectAll("obliquetext").data(data).enter().append("g") 
    .attr("transform", function (d,i) {return "translate(" + (i*40+100) + ",55)" +
                                            " skewX(" + (i*10-40) + ")"; });
  obliquetext.append("text")
	  .attr("font-family", "Saira")
	  .text( function(d) {return d;});	
	
// Caps via javascript toUpperCase() and toLowerCase
// Use <tspan> to apply to subsets of strings
svg.append("text")
    .attr("x",10).attr("y",75).text("Case:")
var casetext = svg.selectAll("casetext").data(data).enter().append("text") 
  .attr("x",function(d,i) {return i*40+100;})
	.attr("y",75)
	.attr("font-family", "Saira");
  casetext.append("tspan")
    .attr("font-variant","small-caps")
  	.text( function(d,i) {return i<5 ? d.substring(0,i).toLowerCase() : 
                                       d.substring(0,i%5).toUpperCase(); })
  casetext.append("tspan")
    .attr( "font-variant",function(d,i) {return i<5 ? "normal" : "small-caps";})
  	.text( function(d,i) {return d.substring(i%5,10).toLowerCase();});
  
// Typeface via font-family:
svg.append("text")
    .attr("x",10).attr("y",95).text("Typeface:")
svg.selectAll("fonttext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",95)
  	.attr("font-family", function(d,i) {return fonts[i];})
  	.text( function(d,i) {return d;});	
	
// Underline via text-decoration.
// Note some inconsistency on Firefox, IE, etc. 
// Since underline in SVG has almost no variants, instead here the length of the underline is varied:  
svg.append("text")
    .attr("x",10).attr("y",115).text("Underline:")
  var uline = svg.selectAll("ulinetext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",115)
  	.attr("font-family", "Saira Extra Condensed")
  uline.append("tspan")
  	.attr("text-decoration","underline")
	  .text( function(d,i) {t=d+"\u2009".repeat(7); return t.substring(0,i);})
  uline.append("tspan")
    .attr("text-decoration","strike-through")
	  .text( function(d,i) {t=d+"\u2000".repeat(7); return t.substring(i,10) ;}); 

  // Widths via font-family (use a font with many widths):
  svg.append("text")
    .attr("x",10).attr("y",135).text("Width:")
  svg.selectAll("widthtext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
	  .attr("y",135)
	  .attr("font-family", function(d,i) {switch(i) {
										case 0: case 1: return "Saira Extra Condensed"; break;
										case 2: case 3: return "Saira Condensed"; break;
										case 4: case 5: return "Saira Semi Condensed"; break;
										default:  return "Saira"; }
										})
	  .text( function(d,i) {return d;});
	
// Tracking via letter-spacing:
// Note some inconsistency on Firefox, IE, etc.
svg.append("text")
    .attr("x",10).attr("y",155).text("Spacing:")
svg.selectAll("tracktext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",155)
  	.attr("letter-spacing", function(d,i) { return i*.05-.1 + "em";})
  	.attr("font-family", "Saira Condensed")
  	.text( function(d,i) {return d;})
	
// Baseline shift via dy
// Note provide a list for dy, each character is shifted by each successive dy value
svg.append("text")
    .attr("x",10).attr("y",175).text("Baseline:")
svg.selectAll("baseshifttext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",175)
  	.attr("dy", function(d,i) { return Math.sin(i)*3 +" "+ Math.sin(i+3)*3 + " " + Math.sin(i+6)*3+" ";})
  	.attr("font-family", "Saira")
  	.text( function(d,i) {return d;});
	
// Outline via stroke
svg.append("text")
    .attr("x",10).attr("y",195).text("Outline:")
svg.selectAll("outlinetext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",195)
  	.attr("fill","white")
  	.attr("stroke","black")
  	.attr("stroke-width",function(d,i) {return i*.15+.15;})
  	.attr("font-family", "Saira ExtraBold")
  	.text( function(d,i) {return d;});
	
// Combo, color + font
svg.append("text")
    .attr("x",10).attr("y",215).text("Font+Clr:")
svg.selectAll("combotext").data(data).enter().append("text") 
    .attr("x",function(d,i) {return i*40+100;})
  	.attr("y",215)
  	.attr("fill", function(d,i) {return clrs[i];})
  	.attr("font-family", function(d,i) {return fonts[i];})
  	.text( function(d,i) {return d;});
	
// Combo: fake dropshadow
svg.append("text")
    .attr("x",10).attr("y",235).text("Dropshadow")
var dropshadow = svg.selectAll("dropoffset").data(data).enter().append("g")
    .attr("transform", function (d,i) {return "translate(" + (i*40+100) + ",235)"; });
  // first draw the shadow text, slightly offset
  dropshadow.append("text") 
    .attr("dx",function(d,i) {return Math.sin(i)*1.6;})
  	.attr("dy",function(d,i) {return Math.cos(i)*1.6;})
    .attr("font-family", "Saira SemiBold")
  	.text( function(d) {return d;});
  // then draw the top text, in a different color
  dropshadow.append("text")
	  .attr("fill", function(d,i) {return clrs[i];})
	  .attr("font-family", "Saira ExtraBold")
	  .text( function(d,i) {return d;});
	
// Combo: Oblique + weight + baseline
svg.append("text")
    .attr("x",10).attr("y",255).text("Ob+Wt+Base")
obliquetext = svg.selectAll("obliquetext").data(data).enter().append("g") 
    .attr("transform", function (d,i) {return "translate(" + (i*40+100) + ",255)" +
                                            " skewX(" + (i*10-40) + ")"; });
  obliquetext.append("text")
  	.attr("dy", function(d,i) { return Math.sin(i)*3 +" "+ Math.sin(i+3)*3 + " " + Math.sin(i+6)*3+" ";})
  	.attr("font-family", "Saira")
  	.attr("font-weight",function(d,i) {return i*100+100;})
  	.text( function(d) {return d;});
              
            
!
999px

Console