Library for Foundry VTT which provides module developers with a means to modify the Ruler class in core Foundry VTT code, while reducing the likelihood of conflict with other modules. Also aims to make certain overrides of the Foundry ruler easier to accomplish.
Add this Manifest URL in Foundry to install.
Enable the Module in your World's Module Settings. That's it! As a module library, there are no user-facing settings.
Your options parallel that of libWrapper. Those options are shamelessly copied and adapted here:
- Adapt the shim provided by libWrapper shim.
- Write your own. Please do not make your custom shim available in the global scope.
-
Trigger a different code path depending on whether libRuler is installed and active or not. For example:
Hooks.once('libRulerReady', async function() { // FLAG ANYTHING YOU NEED GIVEN THAT LIBRULER IS ACTIVE } // or if(game.modules.get('libruler')?.active) { // DO LIB-RULER VERSION }
or
-
Require your users to install this library. One simple example that achieves this is provided below. Reference the more complex example in the libWrapper shim if you prefer a dialog (including an option to dismiss it permanently) instead of a simple notification.
Hooks.once('ready', () => { if(!game.modules.get('libruler')?.active && game.user.isGM) ui.notifications.error("Module XYZ requires the 'libRuler' module. Please install and activate this dependency."); });
Note that if you choose this option and require the user to install this library, you should make sure to list libRuler as a dependency. This can be done by adding the following to your package's manifest:
"dependencies": [ { "name": "libruler" } ]
libRuler overrides methods of and adds methods to the base Foundry Ruler class. Use libWrapper to wrap functions needed by your module. Additional documentation describes the functions available:
- Ruler class overrides. Ruler methods overriden by libRuler.
- Ruler class additions. Ruler methods added by libRuler.
- RulerSegment class. New class added by libRuler, representing the segment between two waypoints (including origin and destination as waypoints). Accessible at
window.libRuler.RulerSegment
. - Ruler Utilities. Ruler utility methods added by libRuler. Accessible at
window.libRuler.RulerUtilities
.
Examples in the additional documentation sometimes point to branches of other modules. Specifically:
- Examples from Drag Ruler are currently from the forked version.
- Examples from Pathfinding Ruler are currently from the forked version
The expectation is that modules will use libWrapper to wrap one or more functions in the new RulerSegment
class, the new methods added to the Ruler
class, or (rarely) the underlying Ruler
class methods.
The RulerSegment
Class is exposed at window.libRuler.RulerSegment
and can be wrapped similarly to wrapping core Foundry methods, for example:
libWrapper.register(MODULE_ID, 'window.libRuler.RulerSegment.prototype.addProperties', myCoolFunction, 'WRAPPER');
Elevation Ruler has several examples of wrapping libRuler functions.
libRuler's version of Ruler.prototype.measure
, at measure.js now creates a RulerSegment
representing the path between two waypoints (including origin or destination, as appropriate). The sequence of events remains the same, but events are now mostly handled by the RulerSegment
Class. This permits modules to wrap or otherwise modify sub-parts of the Ruler measurement flow without having to re-write the entire measure method.
The RulerSegment
class class functions to represent segments of the ruler when measuring. The key function of RulerSegment
is to break down measurement into three subparts:
RulerSegment.prototype.constructPhysicalPath
.RulerSegment.prototype.measurePhysicalPath
.RulerSegment.prototype.modifyDistanceResult
.
The full flow of Ruler.prototype.measure
is as follows:
Ruler.prototype.setDestination
allows modules to modify the destination point.
For each segment in turn, from the origin outward:
- A new
RulerSegment
is created. RulerSegment.prototype.drawLine
draws the ruler line on the canvas.RulerSegment.prototype.drawDistanceLabel
draws the text label indicating the ruler distance.
Distance label gets the current text, with the following:
4.1. RulerSegment.prototype.text
(getter)
4.1.1. RulerSegment.prototype.totalDistance
(getter)
4.1.1.1 RulerSegment.prototype.totalPriorDistance
(getter)
4.1.1.2 RulerSegment.prototype.distance
(getter)
4.1.2. RulerSegment.prototype.distance
(getter)
RulerSegment.prototype.distance
is cached, but when calculated for the first time, it calls RulerSegment.prototype.recalculateDistance
, which calls RulerSegment.prototype.measureDistance
, which in turn calls:
RulerSegment.prototype.constructPhysicalPath
RulerSegment.prototype.measurePhysicalPath
RulerSegment.distanceFunction
-->canvas.grid.measureDistances
RulerSegment.prototype.modifyDistanceResult
RulerSegment.prototype.highlightMeasurement
highlights grid spaces on the canvas. 5.1RulerSegment.prototype.colorForPosition
5.2.canvas.grid.highlightPosition
RulerSegment.prototype.drawEndpoints
handles drawing the origin, destination, and waypoint
Ruler.prototype.moveToken
is broken up into parts, namely:
- collision test to permit the movement
- animating the token movement
The full flow of moveToken
:
- Return if certain conditions met, such as the token is not available.
Ruler.prototype.doDeferredMeasurements
Ruler.prototype.testForCollision
- For each ray (segment) of the ruler:
Ruler.prototype.animateToken
--> callstoken.animateMovement
Ruler.prototype.endMeasurement
Ruler.prototype._highlightMeasurement
is deprecated, because its functionality is now part of RulerSegment.prototype.highlightMeasurement
.
Ruler.prototype._addWaypoint
and Ruler.prototype._removeWaypoint
are overriden. _addWaypoint
now takes an optional center parameter; if true it will apply canvas.grid.getCenter
to the point. _removeWaypoint
adds a remeasure
option to trigger measurement when removing a waypoint (defaults to true).
'Ruler.prototype.toJSON' and 'Ruler.prototype.update' are wrapped to accommodate Ruler flags.
Flags, which let modules store properties to the instantiated object, are added to Ruler
and RulerSegment
classes:
getFlag
setFlag
unsetFlag
Ruler.prototype._onMouseMove
gains several sub-methods to permit modules more control over when ruler measurements occur: