Advanced drawing
Open vs Closed Geometry
Combining with Boolean operations
- first model to combine, we'll call it "modelA"
- second model to combine, we'll call it "modelB"
- boolean to include modelA's paths which are inside of modelB
- boolean to include modelA's paths which are outside of modelB
- boolean to include modelB's paths which are inside of modelA
- boolean to include modelB's paths which are outside of modelA
Instead of remembering the boolean flag combinations, shortcuts are provided for: Now it is apparent why we need a closed geometry - because we need to know what is considered the inside of a model.
Return value
These function will return a new model object with 2 child models, "a" and "b" which are aliases for the 2 models you passed in.Order of Boolean operations
Combining models with boolean operations is a powerful feature but it can be challenging in some scenarios. Re-modeling your drawing may be necessary to acheive certain results. We will explore the order of operations concept with a sample project. Let's first take a look at our desired end goal:
We can start with all of the building blocks of our design: a star, a plus, and a frame:
The first step is to combine the vertical and horizontal bars of the plus:
Next we will combine the star and the plus:
Let's pause and consider what the plus looks like by itself, after our union operation with the star:
And the star by itself:
They have become open geometries. We cannot call the combine function with an open geometry. But since we combined them, they are a closed geometry when they are together. So, we should create a new model for them together:
Now we can continue, with a subtraction operation. Notice that we should not subtract the starplus from the frame (try that on your own to see what happens) but only from the inner frame:
Expanding paths
Paths can be expanded to produce a closed geometry model which surrounds them perfectly.
Pass a path and a distance to makerjs.path.expand, this will return a new model:
You can also expand all the paths in a model by calling makerjs.model.expandPaths:
Beveling joints
A third parameter can be passed to makerjs.model.expandPaths to specify the number of corners to apply to each joint and end cap:
- 0 (default) - no corners (rounded)
- 1 - one corner (pointed)
- 2 - two corners (beveled)
Outlining a model
Expanding a model's path will surround every path, which sometimes can mean there is an inner and an outer surrounding chain. If you only want the outer surrounding chain, use makerjs.model.outline:
Wireframe technique
Creating a wireframe and using expansion may save you a lot of work. We will demonstrate by creating a wireframe of a truss:
Next we will expand the paths:
Simplifying paths
If you Play the wireframe example above, and click on 'show path names' you will see that many lines have been created as a result of the expansion. This is an artefact of all of the boolean operations with combine. The outmost chain for example, should be able to represented with only four lines. To remedy this, there is makerjs.model.simplify - however there is an important caveat: your model must be originated before you can call the simplify function. This is to make sure that all of the segmented paths share the same coordinate space.
Be sure to play this example, and click 'show path names' for comparison.
Bezier curves
Bezier curves are a fascinating and complex topic too large to cover here, it is recommended that you visit A Primer on Bezier Curves by Mike Kamermans (aka Pomax). Maker.js depends on Pomax's Bezier.js which is a vital site to visit for understanding Bezier curve functionality in depth.
It is important to understand how Maker.js manages the complexity of these mathematical wonders. For this explanation, we will start at the end and work our way backwards to the beginning of the process.
The final representation of a Bezier curve in Maker.js is a model containing a series of circular arc paths which closely approximate the curve. Closer approximation means more calculation time and more arcs.
Prior to generating the arcs, the curve is broken down into a series of sub-curves. It is from the sub-curves that the arcs are generated. Each sub-curve is guaranteed to not have an "S" shape so that it more closely resembles a circular arc. The sub-curves are also broken at their rectangular "boundary box" points so that we are guaranteed that the boundary box tangent points are truly points on the curve and not approximations. In the Bezier.js terminology, these breaking points are known as extrema.
Now we are at the beginning of the process, where you call makerjs.models.BezierCurve with the new operator. You can create both quadratic and cubic Bezier curves. For either type, you may optionally pass the accuracy - the maximum distance between the true curve and the arc approximations. The default accuracy coefficient in Maker.js will produce an accurate and visually smooth curve in a reasonable calculation timeframe.
Create a quadratic Bezier curve in by passing an array of three points - an origin point, a control point, and an end point:
Create a cubic Bezier curve in by passing an array of four points - an origin point, a first control point (relating to the origin point), a second control point (relating to the end point), and an end point:
Be sure to Play these examples, then click "show path names" to see the arcs representing the curve.
Fonts and text
To create models based on fonts, use makerjs.models.Text with the new operator. Pass a font object, your text, and a font size. Each character of your text string will become a child model containing the paths for that character.
Maker.js uses Opentype.js by Frederik De Bleser to read TrueType and OpenType fonts. Please visit the Opentype.js GitHub website for details on its API. You will need to know how to load font files before you can use them in Maker.js.
Loading fonts in the browser
Use opentype.load(url, callback)
to load a font from a URL. Since this method goes out the network, it is asynchronous.
The callback gets (err, font)
where font
is a Font
object. Check if the err
is null before using the font.
Previously, all of our examples ran synchronously and we could use document.write
to output a result.
But now we will need to wait for a font file to download. You will have to take this in consideration in your application.
In the Maker.js Playground we can call playgroundRender().
Here on this page we will insert our SVG into a div
in this document:
Loading fonts in Node.js
Use opentype.loadSync(url) to load a font from a file and return a Font object. Throws an error if the font could not be parsed. This only works in Node.js.
Finally, a phenomenon to be aware of is that fonts aren't always perfect. You may encounter cases where paths within a character are self-intersecting or otherwise not forming closed geometries. This is not common, but it is something to be aware of, especially during combine operations.
Layout on a path
- baseline: number [default: 0]
- reversed: boolean [default: false]
- contain: boolean [default: false]
- rotate: boolean [default: true]
baseline
This is a number, ususally between 0 and 1, to determine where to place each model "vertically" on the layout path. This is a ratio of the parentModel's total height above the x-axis. You may also use a negative number or greater than 1 for interesting effects. Use 0.5 to place a model at the y-center:reversed
This option will not work for a circle. Lines and arcs each have a concept of a directional flow:- line - a line flows from its origin to its end.
- arc - an arc flows from its startAngle to its endAngle, in the polar (counter-clockwise) direction.
contain
You may notice that the red arc's endpoints are in the x-center of the first and last children. To contain the children within the span, set contain to true:rotate
If you wish each child to be placed on the path but not rotated, set rotate to false:Laying out text
Layout on a path works well with fonts and text. See an example here.Solvers
Maker.js provides a solvers module for common trigonometry equations, such as solving triangles.
Next: Model trees.
An open geometry is when any path in a drawing is a dead end. A closed geometry is when all path ends meet and there are no dead end paths. A closed geometry forms an enclosed shape.
Examples of Open Geometry:
Examples of Closed Geometry:
Maker.js works with both open and closed geometries. When your desire is to create a three dimensional object, you will probably be using a closed geometry.