Vulcan: Components Builder


#1

Vulcan draws incredible power from its hugely customisable AddOns system, whereby you can not only Fork and edit our Global Extensions, but you can build your own custom Components from scratch.

New Component Form

The Component Builder

We’ve made the Components builder interface, based on and powered by the Vue.js framework. If you know a little javascript and can find your way around a Vue component, then you can build powerful Vulcan Components.

Components Library

A Simple Example

Let’s dive straight in and build our first simple Component. Like all Vue components, we have 3 sections:

<template>
<script>
<style>

Let’s start with a simple template:

<template>
    <div :class="fromClass">
      Text
    </div>
</template>

and some basic styles

<style scoped>
    .text-user {
        color: #000000;
    }
    .text-bot {
        color: #ffff00
    }
    .text-none {
        color: #ff0000;
    }
</style>

Note that the style tag uses the scoped attribute, which means that these styles are scoped to this Component only.

Ok, on to the script

<script>
    module.exports = {
        name: 'ComponentName',
        props: {
            from: {
                type: String,
                default: 'none'
            }
        },
        data: function () {
          return {}
        },
        methods: {},
        computed: {
            fromClass () {
                return "text-" + this.from
            }
        }
    }
</script>

This is the simplest kind of bootstrapped structure for our Vue component.

name: This enables us to register our component for use inside other components
props: This is where we declare any data we would like to be provided to our component, e.g. from the parent. In our example, we’re going to pass in whether a message is sent from a User, a Bot or None and change the colour of the Text accordingly.
data: For holding data in our Component state, we’re not using it in this example
methods: Functions that we can call inside our component
computed: Similar to methods, but designed to simplify your expressions that you may be inclined to put in your templates. Vue docs state:

computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed.

So now, when I preview our Component in the Result tab and change the initial default Props value, we can see that the text colour will change accordingly.


#2

We can further improve this example through some better layout logic.

Inside our transformGeneratePersonObjects() method

Let’s get the position of our current Object to reference

const { x, y } = this.baseObject.position;

And we shall also reference the size of our current Object

const {width} = this.baseObject.size;

A few options for our layout:

let maxInLayer = 5;
let index = - maxInLayer/2;
let offset = 100;

Now we iterate over the shareholders array

this.shareholders.forEach(shareholder => {
            if (index > maxInLayer/2) {
                maxInLayer++;
                offset += 200;
                index = -maxInLayer/2;
            }
          const position = {
            x: x + width+offset,
            y: y + index * 200
          }

         // refactor of setting the notesLines content
          const { sourceName, totalShareholding, totalShareholdingPercentage } = shareholder;
          const content = `${sourceName} holds ${totalShareholding} shares, equating to ${totalShareholdingPercentage}% of the available shares.`;

          // this is the magic
          const objectPromise = this.$store.dispatch('object/create', {
            type: "AnalysisTools_PersonObject",
            position,
            info: {
              title: sourceName,
                settings: {
                    title: sourceName,
                    notesLines: [{
                      id: this.guid(),
                      type: "Text",
                      content
                    }]
                }
              }
            })
            
          // Adding connections between original and new object
          objectPromise.then(createdObject => {
            console.log('Created object: ' + createdObject.id);
            this.$store.dispatch("connection/create", {
              from: this.baseObject.id,
              to: createdObject.id
            });
          })
          
          index++;
        })

As you can see, in addition to some slight evolved layout logic, we’ve also extended the Promise handling. When the Promise is returned from the Object create, we then send a subsequent request to the store to create a connection between the original object and the new object.

Overall, the effect is much a much more controlled layout. But with this approach, we could easily add further methods that determine different layouts that users can select according to their preference.

Here’s the result…