Reusable and configurable Wick components

ComponentsWithWick.wick (57.9 KB)

The main interest of the attached animation is to show a way to create reusable and configurable Wick components.

Using the animation

The purpose was to illustrate the basic functioning of business organizations, from customer order to goods delivery.

To run it, click on PLAY ALL, wait that the various warehouses start getting filled, PLAY ALL again to trigger the next flows, until the whole chain can play.
Each flow can be started and stopped individually.

Component-based design

The animation defines and uses 3 components:

  • The Container Component models a warehouse (or any tank, or anything that can be filled in and emptied). It has;

** one property: .$defaultColor
** several custom methods:
- $fill()
- $clear()
- $addToContent(quantity)
- $setContent(ratio)
- $getContent()
In addition,

  • project.$initContainer(contClip, defaultColor = “DarkGreen”, defaultContent = 0) initializes Containers components.

  • The Flow component will empty some containers, and fill some others.

Here are its properties and methods:

  • Properties
    $sourcesList // List of source Containers, and quantities to substract;
    $targetsList // List of target Containers, and quantities to add;
  • Methods
    $areSourcesOK // Checks sources Containers not empty
    $areTargetsOK // Checks target Containers not full
    $okToStart // Source and target Containers both ok
    $updateContainersContent // Adds or substract quantities to Containers if okToStart.
    $setColor // Color of flow, unless is an image

In addition,

  • project.$initFlow(flowClip, sourcesList, targetsList, color = “DarkGrey”) initializes Flow Components.

  • The ON/OFF component starts and stops a given flow.

How to setup the layers

The code defining each component is in a specific layer, prefixed by Code.
There are dependencies, so the order of layers must be respected.

The last layer, CodeConfiguration, contains the code that is specific to this animation: it initializes and configures all components instances used by this animation.

Using the components in a new animation

To use the components in a new animation, copy anyone of them in the animation layer, and give it a meaningful name.
In addition, each CodeXXX layer, except the last one, CodeConfiguration, should be copied and left unchanged.
The CodeConfiguration layer has to be present as well, but its content is specific to each animation. Its purpose is to initialize each animation components using the project.$initXXX() functions.

1 Like

Oh! Cool, is that a primitive class implementation?, you could use JS’s default classes:

class Product {
  constructor(name, brand, expiry) {
    // Now remember, JS was modeled after Java and C(++)
    this.name = name;
    this.brand = brand;
    this.expiry = new Date(expiry).getDate();
    this.factoryDate = new Date().getDate();
  }
 get message() {
    // A getter works like a variable, but it's a function
    return `Hi! I'm a ${this.brand} ${this.name}! I expire in: ${product.expiry} (I was produced in ${this.factoryDate}.)`;
  }
  logMessage() {
    console.log(this.message);
  }
  static filterFromBrand(brand, ...products) {
    // Static methods are accessible without creating a class.
    // ...arg is a splat, meaning many items have been turned into a array.
    return products.filter( (product) => product.brand === brand ); // If this returns true, keep in new array, if false don't.
  }
}

class UnlabeledProduct extends Product {
  constructor(name, expiry) {
    super(name, "Unlabeled", expiry); // gets everything from Product, but with different args.
  }
  static filterUnlabeled(...products) {
    return Product.filterFromBrand("Unlabeled", products);
  }
}

How do you learn this stuff…

MDN:

Hi @noobfield,
Sounds interesting and a clean way to implement class extension.
But I can’t immediately see how to transpose your example to mine, because I don’t know which JS class a given wick object (clip, timeline, frame, project…) is mapped to.
Happy to give it a try, with additional info. A sample based on my animation, for example the Container extension, would certainly help.

Rethinking of it, if I understand well what you are proposing, I can see some complexity to build the components from Wick’s JS classes. The reason is that, in the approach I’m proposing, the components combine clips and paths. The extra properties and methods relate to this combination, not to the individual constituents.
Combining is easy and easily maintainable when done visually. If coded purely in JS, it means that all this combining has now to be done by code, building on top of the standard Wick classes. Unless I’m missing something, it looks to me more complex, more technical. Still doable, but the target audience would not be the same I guess. The required skills would shift from animating to programming.

I like your idea since:

  • It separates code from clips, which cloned clips’ scripts will be duplicated instead of referenced.
  • Simplifies searching for code
  • Makes everything look neat.

I also found about a thing:

var myClip = new Wick.Clip();

function update() {
  this.rotation++;
}

var updateClip = update.bind(myClip);

myClip.onEvent('update', updateClip);
class Spinny extends Wick.Feature {
  constructor() {
    super();
  }
  static get classname() {
    return 'Spinny';
  }
  static get clipname() {
    return '$spin';
  }
  static clipUpdate() {
    this.rotation =+ this.rotationSpeed
  }
  static clipLoad() {
    console.log(`Clip ${this.name} loaded`);
  }
  // Other methods
}
// V.S

function Spinny() {
  Wick.Feature.call(this);
}
Spinny.clipLoad = function() {
  console.log('Spin spin!');
}
Spinny.prototype.classname = "Spinny"
// ...

You got the point. Without this design, to create a new clip, after copying it visually, you would need to make changes (visual and code) in different places in the clip.
Here, for say a Container component in the attached example, after copying it on the canvas, the only thing that is needed for it to work properly, is to add this line in the Configuration layer:

project.$initContainer(inRed, “DarkRed”, 0);

Another benefit is the time and errors saved when the code is updated. When new features are added, or existing features improved, the code needs to be changed in one place for all components to be updated at once. No need to make the changes to all components individually.
Also, when it becomes collaborative, one or a small number of people need to work on the tricky part, that is, implementing properties and methods. Then many others can use them, without even knowing how it is coded.

And by the way, I’ve not invented anything here. It’s been decades that the benefits of “componentizing” the code have been identifed. This is just a transposition to animations in Wick.

Although I understand the code, I didn’t get the point. Could you give more details?
Thank you.

Functions in JS, just like about everything are classes.

function.bind is a wrapping method, which allows this:

function runTick() {
  this.tick++;
  return this.tickMethods.map( (method) => method.call(this) ); // .call calls with a thisArg, then arguments.
}

var myObj = {
  tick: 0,
  cool: 0,
  tickMethods: [ () => this.cool++; ]
}

runTick(); // X: this will be the global environment.
runTick.call(myObj, 1, 1); // !: this will be myObj, arguments are: [1, 1]
runTick.apply(myObj, [1, 1]); // Same as .call, but args are a array.
var objTick = runTick.bind(myObj, 1, 1); // Now, you have a reusable function.

objTick(1, 1); // same as the last two

@noobfield, I think I’m now gettting your posts: were you meaning that the componentization which I’m proposing, is also reflected somehow in the Javascript structure?

If so, this is not just chance. I’ve just proposed a way to implement some basic concepts of the Object Oriented (OO) Modeling approach, which many modern languages, as JS, are also implementing. So no surprise then! Same root :slight_smile:

OO Modeling is not bound to programming languages. It can be applied to many cases where modeling obects of the real world is needed. I’ve just used the available features of Wick to implement OO. For example:

  • Component layers gathering the code of a given type of object, mimic a Class.
  • Then structuring the code in each component layer in properties and functions implements OO properties and methods. This can be paralleled with variables in a JS Class Constructor, and functions within the JS Class definition.
  • And also,

project.$initXXX(myXXXClip, inputParameters)

parallels this JS instruction:

var myXXXClip = new XXXClipClass(inputParameters);

Altoghether, just a Wick compliant implementation of OO Modeling.

We can also do something like this:

project.$create({
  name: "Spinny",
  clipName: "$spin",
  ctor() { console.log(1) },
  update() {
    this.rotation++;
  },
  load() {
    console.log(`${this.uuid} ${this.name} loaded.`);
  }
  $doA360() { // everything that starts with $ is a method.
    this.rotation += 360;
  }
  killed() {
    console.log(`${this.uuid} ${this.name} killed.`);
  }
});

// Other Script

project.$init("Spinny"); // all "$spin"
project.$init("Spinny", myClip) // only myClip

project.$call("Spinny", "doA360");

project.$kill("Spinny"); // kills all active "Spinny"

Thank you @noobfield for this new code.
When you have some time, could you provide a simple .wick showing what you mean? It would help me understand, as I’m not sure I’m getting the point so far.
Thank you.