Can I inject JointJS as an AngularJS module like any other library?
Asked Answered
N

2

6

I have an app with angular and I need to use this library http://www.jointjs.com/, So I downloaded the joint.min.js and joint.min.css and placed their routes in the index.html but I don't know what to put in the app.js to inject it and I keep getting injection error from angular. Is it possible that this is not the way to do it? I googled a lot but didn't find any approach. I will appreciate any help, thanks in advance!

Nathanaelnathanial answered 2/4, 2015 at 13:32 Comment(0)
G
16

If you want to render a Jointjs diagram in your angular application, then that is pretty easy to do. In my case I encapsulated the Jointjs code inside an angular directive and passed in the Jointjs graph object. The (simplified) directive looks like this:

(function () {
    'use strict';

    var app = angular.module('app');

    app.directive('jointDiagram', [function () {

        var directive = {
            link: link,
            restrict: 'E',
            scope: {
                height: '=',
                width: '=',
                gridSize: '=',
                graph: '=',
            }
        };

        return directive;

        function link(scope, element, attrs) {

            var diagram = newDiagram(scope.height, scope.width, scope.gridSize, scope.graph, element[0];

            //add event handlers to interact with the diagram
            diagram.on('cell:pointerclick', function (cellView, evt, x, y) {

                //your logic here e.g. select the element

            });

            diagram.on('blank:pointerclick', function (evt, x, y) {

                // your logic here e.g. unselect the element by clicking on a blank part of the diagram
            });

            diagram.on('link:options', function (evt, cellView, x, y) {

                // your logic here: e.g. select a link by its options tool
            });
        }

        function newDiagram(height, width, gridSize, graph, targetElement) {

            var paper = new joint.dia.Paper({
                el: targetElement,
                width: width,
                height: height,
                gridSize: gridSize,
                model: graph,
            });

            return paper;
        }

    }]);

})();

If you need to interact with your model through the diagram, use the Jointjs event handlers and hook them up to functions on your scope in the directive (as shown in the code above).

To use this in your view:

<joint-diagram graph="vm.graph" width="800" height="600" grid-size="1" />

In my case I create the graph in the first case by using the Jointjs graph.fromJSON function from my controller (strictly speaking, this is in a data service component that is called from my controller) and then just add this to the scope.

function getDiagram() {
    return datacontext.getDiagram($routeParams.diagramId).then(function (data) {
        vm.graph.fromJSON(JSON.parse(diagramJson));
    });
}

This approach works OK for adding and removing elements and links from the diagram and for dragging things around. Your controller code just works on the graph object and all the updates to the diagram rendering are handled by Jointjs.

function addCircle(x, y, label) {

    var cell = new joint.shapes.basic.Circle({
        position: { x: x, y: y },
        size: { width: 100, height: 100 },
        attrs: { text: { text: label } }
    });
    graph.addCell(cell);
    return cell;
};

Jointjs is a great library, but it is based on Backbone.js for databinding. The only problem I have found is that it doesn't play particularly well with angular in cases where you want to edit diagram element properties (e.g. the contained text) using angular. For example, I have a properties pane (an angular view) that is used to edit the selected diagram element properties.

I made a hacky workaround for this that I am too ashamed to put on SO ;o) I'm still learning about angular/joint/backbone so hope to have a better approach by the time I finish my project. If I do, I'll post it here. Maybe someone more expert than me could already do better though - I'd be glad to see a better approach posted here.

Overall, this directive works as an approach, but it feels like a superficial integration between Angular and Jointjs. Essentially the directive creates an "island of jointjs" inside the angular application. I would like to find a more "angular native" way of doing this, but maybe that would require a re-write of Jointjs to use angular instead of backbone...

P.s. If you already have jquery in your application, you can get a version of joint that excludes jquery from the Jointjs download page:

http://www.jointjs.com/download

Gleda answered 9/4, 2015 at 11:47 Comment(4)
I believe jointjs uses backbone, not knockoutPhelgon
Hello! Just wondering if you had any further revelations regarding AngularJS integration? I'm about to start on this myself and I'm particularly interested in the shapes of model data and how that can be interacted with via the Joint diagrams? Thanks for any response :)Paramnesia
@ChrisBrown: I did make some more progress as it happens. You can see it here #34412307Gleda
@MikeGoodwin Ah yes thanks, it appears that I'm the one that upvoted that answer so must've found it on a Google hunt :pParamnesia
E
2

Found a great GitHub repo that tries to do just what your asking. If its not exactly what you wanted its still a great inspiration source!

Expiate answered 21/7, 2015 at 18:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.