Toolpic Core
Core processor of Toolpic, developed for Fridays For Future. This is not the whole project but the core library, that is used by the client and the rendering server.
Disclaimer
Before you are able to understand ToolpicCore and the related software around such as the default client or any rendering system, you should be familiar with the following:
Project Structure
Install
$ npm install toolpic
Usage
Please note, that Toolpic is an UMD module, that is made to be used within an environment that supports UMD modules
If you want to use toolpic independently as a standalone system, you have to import the module into global scope using a <script>
tag
Example
; console;
Import into global scope
To import Toolpic straight into your global scope, use the toolpic.js
file within the lib
folder or just jsdelivr's npm cdn.
Disclaimer 2: The toolpic project is divided into a lot of projects such as this toolpic core but also a (server) rendering API, a server implementation and, of course, a client implementation. The default client implementation is the one, we've developed for Fridays For Future. Because the way, template modules are designed, is related to some other parts of the toolpic project, this documentation also explains these parts even if they are not a part of toolpic core. But they are reproduceable and the recommended way how to use it even if you implement your own use case.
Toolpic Core
// Import Renderer; // 'templateModuleNameSpace' is an imported object containing a pre-compiled VueComponent and some additional properties const render = templateModuleNameSpace;// Ready to use
The toolpic core system works with pre-compiled VueComponents that can be rendered using the render()
function. So, note:
- Each template needs to be a valid VueComponent that is pre-compiled.
- Because we're normally using
.vue
Single File Components as templates, the template object looks like a ModuleNameSpaceObject and the component lives on thedefault
property.
API
With your constructed Toolpic
instance you can do certain things, that are more less controlling the VueComponent behind it. To understand the behavior of some methods (e.g. seekAnimations()
) it is useful to read the whole documentation including the part about structuring templates.
data
The data
controller is a proxy that connects your instance straight to the data controller of the VueComponent behind.
data
[GET] If you are getting any property within data
such as data.foo
, you get an object containing the requested key
and the __value
.
E.g, the return of render.data.foo
would be:
key: 'foo' __value: 'bar'
data
[SET] To set any property, just do as you would do normally with objects:
renderdatafoo = 'bar';
dataset
To get or set the data to the VueComponent's data controller, you also could use dataset
. When getting dataset
object returns all properties within the VueComponent's data controller as a new assigned object.
If you are setting dataset
, all properties will hardly overwrite the existing ones within the VueComponent's data controller.
const allData = renderdataset; // Overwrite datarenderdataset = foo: 'bar'
listenForResources()
Use listenForResources()
to listen for all resources such as images to finish loading.
render;
Events
update
or set
The update
(alias set
) event will be fired when any update occurs on the data
controller of your instance.
render;
kill
The kill
events will be fired when the kill()
method is applied (destroys the VueComponent)
Methods
restartAnimations()
This method is used to restart all animations that are returned by __animate()
method within the methods
object of your (template) component.
More about that below.
seekAnimations(timestamp)
This method is used to seek all animations to a given timestamp.
kill()
kill()
emits the kill
event and destroys the VueComponent.
Directives
Theoretically you could set every possible mathematically relation just using the properties and Vue.js. But sometimes this would need expressions that are too long to handle. Some of these situations are solved by Toolpic Vue Directives. These are directives that bundled with toolpic
and provided by SuperTemplate
which you should use to extend from by default.
Remember: Because each template is a valid VueComponent, you could also ship specific directives or custom components just for one single component.
Anyway, the Toolpic Vue Directives also can be imported manually from toolpic
module:
;
v-dynamic
Note: v-dynamic
is deprecated for the most common use cases. Use <Dynamic>
component instead.
v-dynamic
is a pretty cool directive that handles a dynamic size of any element you want to.
In detail, this means that the element scales up to a maximum width or a maximum height but never gets bigger than any of them.
<!--any content here--> My dynamic Text <!--any content here-->
This is very cool to use if you have an element that has a dynamic size, which yo don't know when developing a template (e.g. text elements).
v-pos
This positioning directive will translate the element relative to its own boundings to an absolute position within the graphic. Using this directive makes it possible, to originate any element dynamically related to its size in real-time.
<!-- Center of <g> (0.5,0.5) will be at 600,600 (absolute position in view box) -->
v-scaleimage
Often, an image has to fit into a rect as background-size: cover
would normally do. Because this is not offered by SVG, you can use the v-scaleimage
directive to get the same result.
The value of v-scaleimage
is the position of the image relative to its own size. It is a value between -1
and 1
(-1
= 100% left or top and 1
100% right or bottom). The transform-origin
should always be at center because, transform
methods are used to scale and fit the image.
Note: Because the directive is just scaling the image up, it is not cropped by default. Depending on the use case, a mask or clip-path cropping the image would be nice.
Toolpic Custom Components
Some other routines are solved with Toolpic Vue Custom Components. As the directives, they are shipped through the toolpic
core system too. They also are provided by SuperTemplate
which you should use to extend from by default.
Anyway, the Toolpic Vue Custom Components also can be imported manually from toolpic
module:
;
Dynamic
The <Dynamic>
component does the exact same as the v-dynamic
directive and is the recommended solution for dynamic sizing elements. Both solutions are doing more or less the same and both will be kept up to date as long as v-dynamic
is still the better option a some very special use cases. All in all, <Dynamic>
is much cleaner one, supports relative origins and will never flicker while v-dynamic
sometimes is flickering because of rounding behavior.
<!-- Any content here --> Some text that is feared to become too big... <!-- Any content here -->
width
width
defines the maximum width of the contained slot.
height
height
defines the maximum height of the contained slot.
origin
origin
defines the relative transform-origin
within the bounding box of the slot using two values between 0
- 1
.
E.g., a total centered position would be 0.5 0.5
.
Note: When using relative origin
the first time with text, it may seems inaccurate. This is just because the bounding box of a <text>
element will overlap your x
and y
coordinates by a factor depending on the used font. Because this is always a small factor, it will just confuse you if you are scaling up or down with very high deltas. Generally, this factor could be tricked out by setting the value to something close to your intention vallue (0
or 1
) such as 0.05
or 0.95
. But mostly, this is harmless.
MultiLine
Often, you have an array of text lines that needs to be formatted correctly. Because SVG does not offer any clean solution, you would need to create a Vue v-for
loop each time that handles the padding, margin, line height and all the other stuff.
To automate this routine, you can use the <MultiLine>
component. Here, you can pass everything you need just using attributes.
relative
: Two values between0-1
that are describing the origin point that is used to set the element#s position (0.5 0.5
= centered)lineheight
: Line heighttext
: Array containing all linesbackground
: Background color of rectpadding
: Padding to background rectalign
: Inner align of the textcss
: Stylesheet for the<text>
element behind the magic
Toolpic Helpers
To control data in a routine way, you can use some custom methods that can be accessed within the Vue environment just as the directives or the custom components, there are Toolpic Vue Helpers. Such as Toolpic Vue Custom Components and Toolpic Vue Directives, they are also provided by SuperTemplate
which you should use to extend from by default.
Anyway, the Toolpic Vue Helpers also can be imported manually from toolpic
module:
;
textToMultilineFormat()
This method takes a given multiline text (Array) to a specific graphically ratio. That means, you do not have to care the user about when to set a linebreak to fit in perfectly into a 1:1 or 16:9 image. For example, it is used within the Quote
template in which the typed quote has to fit into the image perfectly and a user is not able to devide the linebreaks while writing the quote.
String
that should be formatted to the given ratio (e.g.1
)- Ratio the text has to be formatted to
- Chars per line: Value about the average ratio of each char in the used font (e.g.
0.3
-0.4
). This depends to the font and is just an average value. - Boolean value wether a more correct algorithm should be used. Just use
false
if it seems to be to slow when usingtrue
Template Structure
Disclaimer: What you are doing at this point is not just a part of toolpic core (this npm module) but some paradigms are more or less best practice that are implemented within the default client (Fridays For Future). Because you can program any client using the toolpic core, you also could implement your completely own solution for templating (the template sjust need to be valid VueComponents) or a lot of things else.
A pre-compiled template that can be given as argument to Toolpic
looks like the following:
default: name: 'MyTemplate1' data: <Function> render: <Function> methods: <Object> directives: <Object> components: <Object> width: 1200 height: 1200 type: "image" format: "jpg" fields: smartActions: alias: "Instagram" video: <Object>
As you can see, the default
property is just a normal VueComponent. Learn more about them here.
Template API Reference
default
The default
property represents a pre-compiled VueComponent. Read more about them here.
But there are some things about any Template VueComponent you should keep in mind:
Even if these components are normal VueComponents, some properties or methods are required to access all features of Toolpic. E.g, __animate()
within your methods
object is used to animate a video
template. Or the data()
method returns the data controller you are using for templating. .Read more about that below.
width
The width
is used to specify the width of any template and while the server rendering process.
height
The height
is used to specify the height of any template and while the server rendering process.
type
The type
is mostly used for display purposes and specifies what kind of format
's are available.
The value can be image
or video
.
format
The format
depends on what a kind of type
you specify.
Depending on your type
, possible values are:
type | possible values |
---|---|
image |
jpg , png |
video |
mp4 , mov |
alias
The alias
property is just any string, that will be used as an alias for the current template. This is necessary because in some applications you would group two templates together more or less as "one template" because they are just different in format/ratio (such as 1:1 vs. 16:9). In these cases you need an additional name for each template.
video
The video
object contains additional properties that are used for templates of type
: video
to specify rendering process such as frameRate
or encoding parameters.
Looks like the following:
// The duration of the video sequence (that will be previewed and rendered) duration: 2000 // Frame rate for rendering process (on client side, it is high as possible) frameRate: 24 // Video codec to encode, please have a look at ffmpeg's accepted vcodec values vcodec: "libx264" // Pixel format to be used, please have a look at ffmpeg's accepted pix_fmt's values pix_fmt: "yuv420p"
fields
The fields
array contains descriptor objects that describe input fields for the client. Read more about Field Components below.
A field object looks like the following:
// This property will be used by the related Field Component to interact with the data controller of your Template Component key: "pos" // Just a text that will displayed within the client description: "Image Position" // Field Component you want to control the 'key' component: Slider // Slider is a FridaysForFuture Client implemented component that hosts a range slider // Specific properties that are required by the Field Component above // They are absolutely props: // In this case of a range slider the minimum range min: -1 // In this case of a range slider the maximum range max: 1 // // In this case of a range slider interval steps of the slider step: 001
component
is a Field Component, that will be imported locally in your template script. More about them below. For example, with Fridays For Future Germany we are using are Slider
, Text
or Textarea
and a lot more.
smartActions
The smartActions
array contains descriptors that describe which properties of the data controller can be attached using Smart Actions. Smart Actions are the optional elements that popup on your client when you long-hold the preview on touch screen. Attention: This property is not fully redesigned for the new API. You should note, that it is not that flexible and modular as you expect when looking at fields
. Documentation is following...
Templating
Because a template is just an moduleNameSpaceObject-looking object containing a valid pre-compiled VueComponent on the default
key, you possibly could create such a template the way you want.
But we recommend to create them as .vue
SFC, so your template xml/html/svg, your component and your styles are scoped together in one single file.
Because a template is just a valid VueComponent
, all the properties you want to use within the VueContext, should be declared within the return of your data()
function.
For example, a template, using a .vue
SFC looks like the following:
<!-- The <svg> element is the root element of our component but theoretically, you could also use any valid html element instead --> <!-- Here, we create a circle element and bind the 'r' attribute to the `radius` property of the component-->
Field Components
If you describe a field using a field descriptor object within the fields
array, you have to set the component
property. This should be a Field Component, but what is such a Field Component? At the end, a Field Component is just a valid VueComponent that is interacting with your client. The client implementation of FridaysForFuture also provides a SuperComponent
that you extend when creating your own Field Component. This is recommended because this SuperComponent
just handles some basic thing such as an easy updating communication to the client. Basically your component should emit an update
event containing the key
and value
you want to update on any Toolpic instance (client-side implementation required, of course). Because your component is designed to be used not just for one specific key of a template but to be used for any amount of different templates controlling any possible key, the component does not know which key
should be emitted if you do not give the trough params
when mounting the component (on client-side of course). To avoid that we have to implement this logic each time we create a new Field Component, there is a very cool SuperComponent
that handles this using $__key
as property/attribute. The Fridays For Future Toolpic implementation uses this property when mounting a component, and we recommend to use the same. The SuperComponent.vue
can be found within the default client but you also can just have a look here:
// $__key is internal property that ships the related key props: "$__key" { return value: null ; } watch: { this; }
With basic knowledge of JS and Vue, the benefit is clear: When we extend our Field Component with this Super Component, we just have to set the value
property and the update
event will be fired. Of course, the client has to bind the $__key
property when mounting the component. And of course, the client has to listen to the update
event.
The implementation in FridaysForFuture's client is (simplified) the following:
This would loop trough an fields
array. This array should be the exported fields
array from the active template (what makes sense).
The component we are mounting is binded trough is
attribute (Vue Syntax) and we also bind the component specific properties (such as min
, max
, step
) + $__key
.
Our Field Component could look like the following (.vue
SFC):
Sounds weird?
Maybe, the modular system with Vue SFC's and everything is not that easy to understand when you're not familiar with front-end development tools as Vue or webpack. If you are not completely understanding the workflow and the dependencies:
- Have a look at Vue.js offical documentation: Vue Basics, Vue Components, Vue Single File Components
- Have a look at some templates within our FridaysForFuture Toolpic client (recommended). The
.vue
files there will explain a lot own their own. - Ask us
Animate a video
To animate a video, you need to return an array containing animejs instances within the __animate()
function you can define within methods
object in your template. To access elements within the template you should use Vue's ref
attribute.
A template component that exports an __animate()
function would look like this:
; { return // Any data to return } methods: { const instance1 = ; return instance1 ; }