Typescript Math Toolkit Function Graphing Engine Update
I’m making very good progress on the Typescript Math Toolkit Function Graphing Engine, so I thought it would be a good time for a comprehensive update. The FGE contains a large number of independent components, some of which have been previously discussed, but are in posts scattered throughout the blog. The purpose of this update is to provide a detailed overview of the engine and its individual constituents in a single post.
The TSMT FGE plots functions of a single, independent variable. It is possible to define the function in ‘freeform’ mode (commonly called infix notation) using a calculator-style syntax. The input is a string representing the general form of a function, i.e. 2*sin(x/2). This format is parsed by the TSMT Function Parser and may be evaluated at specific values of x to create a plot.
Other function definitions include self-plotting functions that are part of a permanent function library (a small set will be included with the TSMT distribution) and Typescript Functions that implement a prescribed Interface for evaluation (more in Interfaces below).
The TSMT Function Parser is currently complete.
I discussed the basic concepts behind run-time line decoration in this post. The formal implementation of line decorators in the engine requires some additional discussion. Although I began writing JS in 1996, I used C++ extensively prior to that, so most all my programming practices are influenced by C++ experience (which is, of course, why I prefer Typescript).
For prior C++ and Actionscript (2/3) developers (TL;DR)
Interfaces serve as important contracts between suppliers of functionality and consumers of functionality. The FGE allows arbitrary line decorators to be defined for plotting individual functions. Line decorators provided in the TSMT distribution may be used or you may implement a custom decorator. The engine, however, must be able to rely on implementation of specific functionality, currently defined in a line decorator Interface.
This defines the specific signatures of each method that must be implemented by a line decorator. The FGE relies on this Interface to be implemented by any line decorator used to plot a function. It is, however, not possible to instantiate instances of an Interface. An abstract base class for all line decorators is provided as part of the FGE.
Many purists insist that all abstract base classes be empty. There is really nothing wrong with using this class to define simple, default functionality. For the FGE, the abstract line decorator implements default, solid-line drawing.
So, how is this class actually used?
An arbitrary number of functions may be graphed by the FGE and each function is stacked on top of the others in layers. Each function is graphed into a GraphLayer. Note that a GraphLayer contains a reference to a specific implementation of an abstract line decorator (_decorator).
By default, solid-line decoration is defined on construction of a GraphLayer. The decorator may be changed in a mutator.
Note the use of Typescript Union types in the definition of the internal function reference. Any function may be graphed that is either a reference to the TSMT Function Parser or a concrete implementation of the TSMT$AbstractPlottableFunction base class.
In order to provide a concrete implementation of a line decorator, for example, simply extend the base class and override the necessary functions. For example,
and the specific implementation of the moveTo() method for dashed-line drawing.
With this approach, the FGE does not care about the specifics of line-drawing, only the baseline implementation. Any function may be graphed with any line-drawing technique that adheres to the specified interface.
Grids and Axes
Axes are completely independent from the FGE and are implemented in two classes, Axis and GraphAxis. The Axis class encapsulates all the computations necessary to manipulate a general axis, including updates of graph (not pixel) coordinate bounds after zooming and panning, computing tic mark values and locations, etc. This class does not perform any graphical operations (partial implementation shown, below).
The GraphAxis class composes an Axis and is used to display a horizontal or vertical axis (with or without tic marks and grid lines) with an optional arrow at one or both ends.
Again, from prior C++ practice, I tend to favor composition over inheritance unless there is a strong ‘is-a’ relationship as in the case of line decorators.
The NumberLine will be converted into one of the Angular 2 components supplied with the 1.0 distribution of the TSMT.
The above classes allow a grid and set of axes to be layered below an arbitrary number of function graph layers. Some additional tools will be provided with the TSMT FGE. These include graph markers and a graph slice tool. Markers are circular objects that can be placed at specific graph coordinates (not pixel coordinates). Markers are draggable inside the extents of a graph. New graph (x,y) coordinates are generated as the Marker is moved. Here is an example from the JSMT.
The green graph is a low-order interpolating polynomial. As each red Marker is moved, the polynomial that interpolates each point represented by the Marker is recomputed and then re-graphed.
The graph slice tool may be aligned horizontally or vertically. It generates x- or y-values as it is dragged between relevant graph boundaries.
The triangular areas are draggable. Values of the x-axis in graph coordinates are generated as the slice tool is moved left or right.
I am currently finishing the tools implementation. The prior implementation was event-driven; the TSMT versions will by fully reactive. The function graphing engine class is about 50% converted to Typescript. I have not yet begun on the library of self-graphing functions.
As mentioned in prior posts, the TSMT FGE is written on top of EaselJS; it is a Canvas-based engine.
There are many classes in the TSMT that involve graphical interaction to truly validate their functionality. The FGE will be at the core of the Angular 2 demo used to illustrate these classes. I will begin work on that demo shortly after A2 Final is released.
Thanks for putting up with such a long post.