ShapeJS Developer Tutorials

In this Tutorial we will learn how to add both 2D and 3D text to scenes.

You could bring in text by putting it in an image, but not only would that be inconvenient for you, it would make it much more difficult for your customers to personalize anything from your shop. Instead, it would be better to add text in directly. Fortunately, ShapeJS has just the tools to do so.

1. 2D Text

Let's make a new mug, this time with some names on it.

The Text2d function creates an image for us, which we can then use to create a height map. With the z depth of the image map we will make from the text, we want to make sure that is is deep enough to get all of a curved surface (like our mug) without having it go through and end up engraving things on the far side we don't want engraved.

function main(args) {
  var height = 100*MM;
  var thickness = 5*MM;
  var radius = 50*MM;
  var h_thickness = 5*MM;
  var h_radius = 35*MM;

  //Create Text
  var text = new Text2D("Testing");
  text.set("fontName","Times New Roman");

  var textMap = new ImageMap(text, 80*MM, 25*MM, 50*MM);
  textMap.set("blurWidth",0.1*MM);
  textMap.set("blackDisplacement", 0.5*MM);
  textMap.set("blackDisplacement", 0.5*MM);
  textMap.set("whiteDisplacement", 0*MM);
  textMap.setTransform(new Translation(radius/3,0,radius));

  //Base Solid shape
  var base = new Union();
  var base_cyl = new Cylinder(new Vector3d(0,-height/2, 0), new Vector3d(0,height/2, 0), radius);
  var base_rim = new Torus(radius-thickness/2, thickness/2);

  var compTransform = new CompositeTransform();
  compTransform.add(new Rotation(Vector3d(1,0,0), Math.PI/2));
  compTransform.add(new Translation(new Vector3d(0,height/2, 0)));
  base_rim.setTransform(compTransform);
  var handle = new Torus(new Vector3d(-radius,0,0), h_radius, h_thickness);

  var seat = new Cylinder(new Vector3d(0,-height/2,0), new Vector3d(0,-height/2+thickness, 0), radius);
  base.add(base_cyl);
  base.add(base_rim);
  base.add(handle);

  //Remove
  var remove_cyl = new Cylinder(new Vector3d(0,(-height+thickness)/2,0), new Vector3d(0,(height+thickness)/2,0), radius-thickness);
  var cup = new Subtraction(base, remove_cyl);

  //Emboss Text
  var mask = new Mask(cup, 0, 0.5*MM);
  mask.setTransform(new Translation(0,0,thickness/2));

  var pattern = new Mul(textMap, mask);

  var emb = new Embossing(cup, pattern);
  emb.set("minValue", 0*MM);
  emb.set("maxValue", 1*MM);
  emb.set("factor", 1);

  //Display
  var s = 100*MM;
  return new Scene(emb,new Bounds(-s,s,-s,s,-s,s));
}

Of course, text is the ideal medium for customization, so why don't we allow the shopper to choose a string of his or her own to emboss onto our mug, rather than try to anticipate what they might want.

To do this we'll both add in user definition for text and try to get the text vaguely centered. We'll need to keep track of the length of the text they put in, and perhaps, as an added bonus, we'll lets them choose the emboss height.

var uiParams = [
  {
     name: "texth",
     desc: "Text height",
     type: "double",
     rangeMin: 0.5,
     rangeMax: 2,
     step: 0.1,
     defaultVal: 1
  },
  {
      name: "text",
      desc: "Text",
      type: "string",
      defaultVal: "Text"
  }
];

function main(args) {
  var height = 100*MM;
  var thickness = 5*MM;
  var radius = 50*MM;
  var h_thickness = 5*MM;
  var h_radius = 35*MM;
  var textr = args.text;

  //Create Text
  var text = new Text2D(textr);
  text.set("fontName","Times New Roman");

  var textMap = new ImageMap(text, 80*MM, 25*MM, 50*MM);
  textMap.set("blurWidth",0.1*MM);
  textMap.set("blackDisplacement", 0.5*MM);
  textMap.set("blackDisplacement", 0.5*MM);
  textMap.set("whiteDisplacement", 0*MM);
  textMap.setTransform(new Translation(-2*MM*textr.length+radius/3,0,radius));

  //Base Solid shape
  var base = new Union();
  var base_cyl = new Cylinder(new Vector3d(0,-height/2, 0), new Vector3d(0,height/2, 0), radius);
  var base_rim = new Torus(radius-thickness/2, thickness/2);

  var compTransform = new CompositeTransform();
  compTransform.add(new Rotation(Vector3d(1,0,0), Math.PI/2));
  compTransform.add(new Translation(new Vector3d(0,height/2, 0)));
  base_rim.setTransform(compTransform);
  var handle = new Torus(new Vector3d(-radius,0,0), h_radius, h_thickness);

  var seat = new Cylinder(new Vector3d(0,-height/2,0), new Vector3d(0,-height/2+thickness, 0), radius);
  base.add(base_cyl);
  base.add(base_rim);
  base.add(handle);

  //Remove
  var remove_cyl = new Cylinder(new Vector3d(0,(-height+thickness)/2,0), new Vector3d(0,(height+thickness)/2,0), radius-thickness);
  var cup = new Subtraction(base, remove_cyl);

  //Emboss Text
  var mask = new Mask(cup, 0, 0.5*MM);
  mask.setTransform(new Translation(0,0,thickness/2));

  var pattern = new Mul(textMap, mask);

  var emb = new Embossing(cup, pattern);
  emb.set("minValue", 0*MM);
  emb.set("maxValue", args.texth*MM);
  emb.set("factor", 10);

  //Display
  var s = 100*MM;
  return new Scene(emb,new Bounds(-s,s,-s,s,-s,s));
}