Closed benjamminf closed 7 years ago
Might be worth considering this approach too: provide a vector initialiser to handle default values. This would allow the transform function to not need to check for undefined's.
warpObject.initVector(([x, y]) => [x, y, x, y])
warpObject.transform(([x, y, ox, oy]) => [x + 1, y - 1, ox, oy])
Normalisation steps:
Each step can be performed independently, but strongly recommended to run all, in the above order. This process should also be explicit.
const warpObject = new Warp(svgElement)
warpObject.normalize() // Runs all
warpObject.normalize(Warp.TO_PATH)
warpObject.normalize(Warp.TO_ABSOLUTE)
warpObject.normalize(Warp.TO_LINE)
warpObject.normalize(Warp.TO_CURVE)
Interpolation and extrapolation should be explicit:
warpObject.transform(transFn)
warpObject.interpolate(threshold)
warpObject.extrapolate(threshold)
This should allow for the most amount of flexibility with when to interpolate/extrapolate points. This would allow for fine-tuning performance.
In reference to the initVector
method above, this could actually just be replaced with a starting call to transform
that does the same thing. Meaning initVector
is redundant.
warpObject.transform(([x, y]) => [x, y, x, y])
warpObject.transform(([x, y, ox, oy]) => [x + 1, y - 1, ox, oy])
Taking inspiration from https://github.com/nfroidure/SVGPathData – create a path parsing/streaming/encoding sub-API that provides an interface to inject transforms when iterating over the path data. The linked API supports everything Warp.js needs out of the box, but it's compile size is unfortunately huge.
On second thought, a simple Array.map
should suffice once the path string has been parsed. The kind of data the parser should output should be like https://github.com/hughsk/svg-path-parser – unfortunately this libraries compile size is far too big as well. A much more minimal parser should be possible.
This should be a good starting point: https://github.com/jkroso/parse-svg-path
Not a fan of the minimal output, and I could probably improve the code to make it more readable. Since it's tiny I'll just rewrite it for Warp.js. Transforms could just be plain functions that are passed to Array.map
New setting: precision – ability to set the numerical precision when generating path strings. Default to 2 (decimal places).
To address #4, I propose two new methods: preinterpolate
and preextrapolate
They will take in both the transform function and threshold, and will interpolate points based on the position of points post-transform. The transform will not actually occur – a second call to transform
will be required.
const transFn = ([x, y]) => [x + y, y / 2]
warpObject.preinterpolate(transFn, threshold)
warpObject.transform(transFn)
It should also only be single-pass, meaning the transformation is applied once, and interpolated based on that. This on it's own will not guarantee perfect quality, as even post-interpolation, those points transformed again might still require more interpolation. It'll be up to the user to call these pre
methods as many times as needed.
It might also be useful to have these methods return a boolean, indicating whether any work took place. This could be exploited with a loop to preinterpolate as many times as needed, until no more interpolation takes place. Obviously, this would be extremely expensive, but some situations might call for it.
while(warpObject.preinterpolate(transFn, threshold)) {}
warpObject.transform(transFn)
The new API should be entirely functional, yet still allow of points to be extended. I propose the following method for distorting points:
This example shows how to transform points and keep track of the original position. The function takes in an array of points where the first two elements can be guaranteed (the x and y positions) but allows returning an arbitrary number of points. The interpolation will also operate on all points, so extended points will still be interpolated.
This method will allow storing velocity vectors and anything else along with all points.