Skip to content
Advertisement

JS-Plumb: (Re-)Draw a line between two elements after clicking

Edit: After trying out different hand-made solutions, I am using JSPlumb and trying to let it visually connect a clicked item from one list with a clicked item from another list (see screenshot).

Basic visual connection

I built upon this Stackoverflow thread and made it work basically, however the code provided there allows multiple connections, i.e. JSPlumb draws multiple endpoints and lines, and it doesn’t react if a ‘Target’ is clicked first. However, in my case there should be strictly only one connection, and JSPlumb should re-connect once I click on another list item on either side. (E.g. I click on ‘Source 1’ and ‘Target 3’, JSPlumb draws the connection. I click on ‘Target 4’, JSPlumb should keep ‘Source 1’ as source and re-set ‘Target 4’ as the target, e.g. now draw the connection from ‘Source 1’ to ‘Target 4’. The same with clicking a different ‘Source’, i.e. the target should stay the same.)

In what way would I need to alter the code in order to achieve the desired re-draw?

CodePen

jQuery(document).ready(function () {  
   var targetOption = {
        anchor: "LeftMiddle",
        isSource: false,
        isTarget: true,
        reattach: true,
        endpoint: "Dot",
        connector: ["Bezier", {
                   curviness: 50}],
        setDragAllowedWhenFull: true
    };

    var sourceOption = {
        tolerance: "touch",
        anchor: "RightMiddle",
        maxConnections: 1,
        isSource: true,
        isTarget: false,
        reattach: true,
        endpoint: "Dot",
        connector: ["Bezier", {
                   curviness: 50}],
        setDragAllowedWhenFull: true
    };

    jsPlumb.importDefaults({
        ConnectionsDetachable: true,
        ReattachConnections: true,
        Container: 'page_connections'
    });

    //current question clicked on
    var questionSelected = null;
    var questionEndpoint = null;

    //remember the question you clicked on
    jQuery("#select_list_lebensbereiche ul > li").click( function () {

        //remove endpoint if there is one
        if( questionSelected !== null )
        {
            jsPlumb.removeAllEndpoints(questionSelected);
        }

        //add new endpoint
        questionSelected = jQuery(this)[0];
        questionEndpoint = jsPlumb.addEndpoint(questionSelected, sourceOption);
    });

    //now click on an answer to link it with previously selected question
    jQuery("#select_list_wirkdimensionen ul > li").click( function () {

        //we must have previously selected question
        //for this to work
        if( questionSelected !== null )
        {
            //create endpoint
            var answer = jsPlumb.addEndpoint(jQuery(this)[0], targetOption);

            //link it
            jsPlumb.connect({ source: questionEndpoint, target: answer }); 
            //cleanup
            questionSelected = null;
            questionEndpoint = null;
        }
    }); 

});

Advertisement

Answer

You were already keeping track of the “source” end of the linked items in a global variable; one way of getting to your desired behavior mostly just requires keeping track of the “target” end the same way. (There’s room for improving this — globals are maybe not an ideal strategy, and there’s some code duplication between the ‘source’ and ‘target’ click handlers, but this should do for demonstration at least.)

  // ...other init variables skipped

  var questionEndpoints = []; // 'source' and 'target' endpoints

  // "source" click handler
  jQuery("#select_list_lebensbereiche ul > li").click(function() {
    //remove existing start endpoint, if any:
    jsPlumb.deleteEndpoint(questionEndpoints[0]);
    // add a new one on the clicked element:
    questionEndpoints[0] = jsPlumb.addEndpoint(jQuery(this), sourceOption);
    connectEndpoints();
  });
  
  // "target" endpoint
  jQuery("#select_list_wirkdimensionen ul > li").click(function() {
    if (!questionEndpoints[0]) return; // don't respond if a source hasn't been selected
    // remove existing endpoint if any
    jsPlumb.deleteEndpoint(questionEndpoints[1]);
    //create a new one:
    questionEndpoints[1] = jsPlumb.addEndpoint(jQuery(this), targetOption);
    connectEndpoints();
  });

  var connectEndpoints = function() {
    jsPlumb.connect({
      source: questionEndpoints[0],
      target: questionEndpoints[1]
    });
  };
});

Working CodePen example

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement