Search code examples
javascriptvue.jsecmascript-6node-modulesjointjs

How to define a custom connector in JointJS


I'm attempting to define a custom connector in JointJS in Vue. Though I don't think this is really a JointJS issue or a Vue issue, but rather my lack of understanding of how Javascript modules work in this context...

I have this code, which seems to match the docs (https://resources.jointjs.com/docs/jointjs/v3.3/joint.html#connectors.custom):

import Vue from 'vue';
let joint = Vue.joint;

joint.connectors = joint.connectors || {};

joint.connectors.CloudConflictConnector = function(sourcePoint, targetPoint, vertices, args)  
{
...
}

Note that Vue.joint is created as a plugin, this way:

const Joint = {
    install: function (Vue) {
        let joint = { g, dia, layout, linkTools, V };

        Object.defineProperty(Vue.prototype, '$joint', { value: joint });
        Vue.joint = Vue.prototype.$joint;
    }
};
Vue.use(Joint);

But when I later attempt to use this connector, findPath() in JointJS throws an error that the connector doesn't exist. The issue appears to be that in findPath, it's importing the connectors module from the npm package. That module obviously doesn't have anything I added to the Vue.joint.connectors property.

If I try to add the function to the module more directly, I get a 'Object is not extensible' error. For example doing something like this in the plugin instead:

import * as connectors from 'jointjs/src/connectors/index.mjs';

const Joint = {
    install: function (Vue) {
        let joint = { g, dia, layout, linkTools, V, connectors };
        joint.connectors.customConnector = ...;

        Object.defineProperty(Vue.prototype, '$joint', { value: joint });
        Vue.joint = Vue.prototype.$joint;
    }
};
Vue.use(Joint);

So I guess the question is how does one properly add a property to a module export in a way that other code that imports the module directly can still see it? I think outside Vue, this would all just work because joint would be a global variable (?)


Solution

  • Part of the problem is the plugin creates a new joint object, which is missing the original import's connectors property.

    However, I believe the plugin should keep the original import and setup the custom connector on that:

    export default {
      install(app) {
        const joint = require('jointjs')
        addCustomConnector(joint)
    
        app.prototype.$joint = joint
        app.joint = joint
      }
    }
    
    function addCustomConnector({ connectors }) {
      connectors.CloudConflictConnector = (sourcePoint, targetPoint, vertices, args) => {
        //...
      }
    }
    

    GitHub demo